Compare commits

..

23 Commits

Author SHA1 Message Date
Patrick Plate 038e546963 feat: archive zoo_backup for home sync 2026-06-24 19:27:14 +02:00
Patrick Plate 02844e4c4a added doc 2026-06-22 11:38:09 +02:00
Lumen e18136baa4 Handover: homelab release tooling for Work Lumen (runbook + template + publish script) 2026-06-22 11:35:03 +02:00
Lumen 1603ddcd5c Homelab release tooling: runbook + port registry + homelab-publish.sh switch script 2026-06-22 11:34:20 +02:00
Patrick Plate ff58ec6add lumen-exchange: cannamanage public-hosting readiness + open auth blocker (for Work Lumen) 2026-06-18 21:47:22 +02:00
Patrick Plate fd84071489 chore(homelab): retire git-sync + mirror Gitea, git.plate-software.de now proxies single TrueNAS Gitea 2026-06-15 14:02:49 +02:00
Patrick Plate 67ed0edbe5 chore(homelab): preemptively mirror inspectflow.wiki via git-sync 2026-06-15 09:49:20 +02:00
Patrick Plate b7ef026dcd chore(homelab): add inspectflow to git-sync mirror repos 2026-06-15 09:46:57 +02:00
Patrick Plate 1a0a56a626 chore(java): consolidate mss-failsafe to single canonical copy
Replace the stale multi-module java/mss-failsafe skeleton (old user-management
prototype) with the active single-module machine-safety inspection app that was
living in its own standalone repo at the repo root.

- Remove old java/mss-failsafe/ multi-module tree (mss, userdata, userManagement,
  mssfailsafe.datalayer, mssfailsafeWeblayer) incl. committed build artifacts
- Add the active app (PrimeFaces 11 / JSF 2.3 / Hibernate 5.6 / iText / POI)
  flattened into java/mss-failsafe/ as the only mss-failsafe in git
- Working tree captured = master tip 2a142b5 + in-progress uncommitted work
  (incl. .github/*.instructions.md AI-context files)
- Archive the standalone repo's 33-commit history in GIT_HISTORY_ARCHIVE.md
  since its .git was not migrated

This is the source of truth / base for the upcoming upgraded rewrite.
2026-06-13 19:55:28 +02:00
Patrick Plate 7a573d7193 docs(lumen-exchange): CannaManage local Docker testing + Playwright e2e plan for Work Lumen
Why curl wasn't enough (hydration + missing auth token), the bug catalogue
(hydration crash, PWA middleware, consent principal bug, and the systemic
'frontend never sends the access token' issue), how to run the stack locally
on the Mac, and the concrete Playwright real-token e2e suite to implement.
2026-06-13 11:00:13 +02:00
Patrick Plate 57800f2518 chore(git-sync): add cannamanage.wiki to bidirectional sync repos 2026-06-12 08:55:45 +02:00
Patrick Plate 4f4372038c feat(lumen-exchange): 420cloud competitor analysis + git-sync bidirectional mirror
- Scraped 420cloud.io: feature matrix, AGB pricing analysis, Club Map legal risk
- Strategic recommendations for Sprint 4: compliance PDF, PWA, QR ID, federation
- Research agenda for Work Lumen (Amazon Q deep dive)
- Add plans/git-sync/ Docker container for IONOS→TrueNAS bidirectional sync
2026-06-12 08:52:36 +02:00
Patrick Plate 86d54a4f28 chore(homelab): update mcp.json after roo-zoo-semble zip 2026-06-11 10:17:55 +02:00
Patrick Plate aa9d877233 Merge branch 'chore/homelab/roo-zoo-semble-zip' 2026-06-11 10:17:33 +02:00
Patrick Plate 4760628661 chore(homelab): zip Zoo Code extension with Semble indexing for roo/zoo 2026-06-11 10:17:17 +02:00
Patrick Plate 31dc6d2174 docs(lumen-exchange): CannaManage code confirmed on IONOS + Work Lumen's code request 2026-06-11 09:59:21 +02:00
Patrick Plate e653d487a8 docs(lumen-exchange): request Sprint 1 code push to IONOS for Sprint 2 start 2026-06-11 09:57:38 +02:00
Patrick Plate 6936675af2 docs(lumen-exchange): merge reply and context update 2026-06-11 09:49:41 +02:00
Patrick Plate 49b0c8b285 docs(lumen-exchange): Homelab Lumen reply + update shared context with Work Lumen's eAU migration details 2026-06-11 09:49:41 +02:00
Patrick Plate e857c1b781 docs(lumen-exchange): first message from Work Lumen to Homelab Lumen 2026-06-11 09:40:55 +02:00
Patrick Plate 649096fc5b docs(lumen-exchange): merge initial exchange folder — README, hello note, shared context + open questions 2026-06-11 09:10:29 +02:00
Patrick Plate c8be9516a8 docs(lumen-exchange): create shared mailbox for two Lumen instances via git.plate-software.de 2026-06-11 09:10:29 +02:00
Patrick Plate c2f4c8fc39 chore(homelab): catchup push — roo modes, mcp servers, cannamanage docs, homelab plans 2026-06-11 09:02:28 +02:00
656 changed files with 58712 additions and 7759 deletions
-1
View File
@@ -37,7 +37,6 @@
"alwaysAllow": [
"webscraper_fetch_links",
"webscraper_fetch_section",
"webscraper_search_hint",
"webscraper_fetch"
]
},
+84
View File
@@ -0,0 +1,84 @@
# AI Context Instructions
## Essentials
- Base Classes: AbstractEntity, AbstractManager<T>, AbstractController<E>
- Fake ID Mechanismus für neue Objekte
- Hibernate.initialize für Lazy Collections
# Architecture Instructions
## Typical Generation Tasks
1. Neue Domain (Entity/Manager/Controller/XHTML)
2. PDF Utility Erweiterung (iText7)
3. Sammel-Speichern (saveAll) bereitstellen
4. Klon-Operationen (IDs null setzen, Collections duplizieren kontrolliert)
5. Fragebogen Zuordnung (add/remove, available list)
## Edge Cases
- Null Entities im save -> return false
- Negative IDs beim remove -> zuerst persistieren oder aus UI entfernen
- Concurrency Refresh: Nach batch Änderungen refreshSelected()
## Do / Don't
- DO: Logging bei jeder Exception
- DO: Konsistente Nutzung von @Transactional bei Schreiboperationen
- DON'T: System.out oder ungefangene Exceptions durchreichen ohne Logging
- DON'T: Business Logik direkt in XHTML Event Handler schreiben
## Upgrade Ideas
- Exception Layer
- Bean Validation
- Service Layer zwischen Controller und Manager falls Logik wächst
---
Aktualisiert: 2025-10-20
## Purpose
Verdichtete Architekturhinweise für automatische Code-Generierung und schnelle Orientierung.
## Stack
- Java EE 8 (javax), WAR
- JSF 2.3 + PrimeFaces 11 + PrimeFlex 2.0
- Hibernate JPA (Persistence Unit: pu_person)
- Log4j2
## Layer
1. View (XHTML)
2. Controller (JSF/CDI Beans, extends AbstractController<E>)
3. Business (Stateless EJB Manager, extends AbstractManager<T>)
4. Persistence (JPA Entities, extends AbstractEntity)
## Base Classes
- AbstractManager<T>: CRUD (save, saveAll, refresh, remove), flush nach Persist/Merge.
- AbstractController<E>: UI State (selected, created, entities), Messages, PDF Utilities, Fake-ID-Erzeugung.
## Entity Lifecycle UI
- Neue Objekte: erhalten negative Fake-ID
- Vor Persist: negative IDs -> null setzen
- save/saveAll entscheidet anhand id == null zwischen persist/merge
## Lazy Loading
- Refresh via AbstractManager.refresh(entity) + Hibernate.initialize(entity)
- Für Collections: dedizierte reload Methoden (z.B. SecurityAreaManager.reloadWithQuestionnaires)
## PDF
- iText7 bevorzugt; Altbestand iText5 (itextpdf 5.5.13) kann später entfernt werden.
## Logging & Fehler
- LOGGER.error(e) bei Fehlern
- Aktuell viele bool Rückgaben; Verbesserungspotential: BusinessException
## Erweiterung Pattern
Entity -> Manager -> Controller -> XHTML
## Schulden / Verbesserungen
- Mischung iText5/7
- Inkonsistente Fehlerbehandlung
- Kein DTO Layer
- Wenige Tests
## Empfehlungen für Generator
- Bestehende Signaturen unverändert lassen
- @Transactional nur bei Schreibmethoden hinzufügen
- Collections initialisieren bevor darauf iteriert wird
---
Aktualisiert: 2025-10-20
+75
View File
@@ -0,0 +1,75 @@
# Architecture Instructions
Aktualisiert: 2025-10-20
## Überblick
Das System folgt einer klassischen 4-Layer Struktur:
1. View: JSF 2.3 / PrimeFaces 11 / XHTML Seiten (Formulare, Tabellen, Dialoge)
2. Controller: CDI/JSF Managed Beans, Zustandsverwaltung & UI-Aktionen (extends AbstractController<E>)
3. Business: Stateless EJB Manager mit CRUD + Fachlogik (extends AbstractManager<T>)
4. Persistence: JPA Entities (extends AbstractEntity)
## Basisklassen Rollen
- AbstractEntity: Basis-ID (Long, Identity), Timestamps, outdated Flag, equals/hashCode nur über ID.
- AbstractManager<T>: CRUD, save vs saveAll, remove / removeAllIn, refresh (Hibernate.initialize), Fehlerlogging.
- AbstractController<E>: UI State (selected, created, entities), Fake-ID-Erzeugung für neue temporäre Objekte, Messaging, PDF Utilities.
## Lebenszyklus eines neuen Objekts
1. UI erzeugt neues Objekt (id == null) -> Controller kann negative Fake-ID setzen falls in Collections benötigt.
2. Vor persist: Falls id < 0 -> setId(null) damit JPA Identity funktioniert.
3. save(): id == null => persist + flush, sonst merge + flush.
4. refresh(): sorgt für Managed Entity + Initialisierung Lazy Properties.
## Negative Fake IDs
- Zweck: Temporäre Unterscheidung mehrerer neu angelegter Einträge im UI bevor persist.
- Erzeugung: createFakeID(Collection<E>) nimmt kleinste vorhandene negative ID - 1.
- Vor persist unbedingt auf null setzen.
## Lazy Loading & Refresh
- Manager.refresh(entity) -> merge + Hibernate.initialize(entity) für Entität.
- Für Collections: spezielle Reload-Methoden in fachlichen Managern (z.B. reloadWithQuestionnaires).
- Nach Batch-Operationen Controller.refrehSelected() (Tippfehler) nutzen; perspektivisch in refreshSelected() umbenennen.
## Transaktionen
- Schreiboperationen annotiert mit @Transactional (Container-managed) in AbstractManager.save / saveAll.
- Fachmethoden, die persistieren oder mergen, sollten ebenfalls @Transactional erhalten (Konsistenz).
## Fehlerbehandlung
- Aktuell: Logging (LOGGER.error) + bool Rückgabe.
- Geplant: Einführung BusinessException für differenzierte Fehlerpfade.
## Erweiterungsmuster (Domain hinzufügen)
1. Entity erstellen (extends AbstractEntity). Optional Named Queries.
2. Manager: @Stateless extends AbstractManager<NewEntity>; spezifische Queries / Reload Methoden.
3. Controller: @Named + Scope (ViewScoped/SessionScoped) extends AbstractController<NewEntity>.
4. XHTML Seite inkl. Referenzen zu Controller (DataTable, Dialoge, Commands).
5. Tests: CRUD & fachliche Spezialfunktionen.
## Typische Fachfunktionen
- Klonen: Quelle re-laden + initialisieren; neue Instanz mit Copy-Konstruktor; Child IDs null; Collections duplizieren kontrolliert.
- Zuordnungen (z.B. Fragebogen): Add/Remove Pattern über Wrapper Entity.
## PDF-Erstellung
- iText7 Nutzung über Hilfsmethoden in AbstractController (Tabellen, Inner Cells, Paginierung).
- Keine neuen Features mehr mit iText5 API implementieren.
## Querschnittsthemen & Roadmap
- Vereinheitlichte Exception Layer.
- Bean Validation (javax.validation) für Eingaben & persistente Konsistenz.
- Test Suite (JUnit + ggf. Arquillian / Integrationstests) ausbauen.
- Migration nach Jakarta EE (Namespace Wechsel javax -> jakarta) perspektivisch.
## Edge Cases & Hinweise
- save(null) => false zurückgeben.
- remove(entity) ohne persistierte ID => false.
- Batch Speichern: leere Liste => true (no-op) statt Fehler.
- Collections initialisieren vor Iteration (Avoid LazyInitializationException).
## Generator Leitplanken
- Bestehende Signaturen respektieren.
- Keine neuen Frameworks ohne Notwendigkeit.
- Logging immer via LOGGER, niemals System.out.
- Für neue Write-Methoden @Transactional hinzufügen.
---
+43
View File
@@ -0,0 +1,43 @@
# Cloning Instructions
Aktualisiert: 2025-10-20
## Ziel
Sicheres Klonen von komplexen Domains (z.B. SecurityArea inkl. Sub-Entities) ohne ID-Kollisionen oder versehentliches Persistieren historischer Referenzen.
## Grundprinzipien
- Nur persistente Quelle klonen (ID > 0) -> Vorher `refresh` zur Initialisierung Lazy Collections.
- Neue Instanzen erhalten `id = null` (oder negative Fake-ID falls im UI direkt angezeigt).
- Child-Entitäten ebenfalls mit `id = null` erzeugen.
## Vorgehen (Muster)
1. Quelle laden (Manager.find) & `refresh`.
2. Copy-Konstruktor oder Factory-Methode: Primitive Felder kopieren, Collections iterieren.
3. Collections: Neue Collection erzeugen, für jedes Kind tiefes Copy erstellen (kein Reuse Managed Instanz!).
4. IDs aller Kinder null setzen.
5. Optionale Anpassungen (Name -> "Kopie von <original>").
6. Rückgabe unverpersistiertes Root-Objekt an Controller.
## Tiefe vs. Flache Kopie
- Tiefe Kopie: Notwendig wenn Kinder eigenständige persistente Entities sind.
- Flache Kopie: Ausreichend falls nur Referenzen (Read-Only) erhalten bleiben sollen; aktuell bevorzugt tiefe Kopie für isolierte Bearbeitung.
## Edge Cases
- Quelle == null -> abort.
- Quelle mit Lazy Collections nicht initialisiert -> Gefahr LazyInitializationException.
- Zyklische Referenzen -> sorgfältig verhindern Endlosschleifen (ggf. bereits geklonte Instanzen in Map tracken).
## Fake IDs
- Wenn Klon direkt in UI Collection erscheint: negative ID via `createFakeID` generieren.
- Vor persist -> ID auf null setzen.
## Verbesserungen
- Einführung eines generischen `CloneService` mit rekursiver Strategie und Zyklus-Erkennung.
- Annotation @SkipClone für Felder die nicht übernommen werden sollen.
## Generator Leitplanken
- Keine Reflection-Magie für tiefe Kopien; lieber explizite Copy-Konstruktoren für Lesbarkeit.
- Reihenfolge: zuerst Root, dann Kinder.
---
+43
View File
@@ -0,0 +1,43 @@
# Coding Guidelines Instructions
## Naming
- Manager: *Manager
- Controller: *Controller
- Entities: Singular Substantive
- Negative IDs: temporäre Objekte
## Style
- 4 Spaces
- Logger statt System.out
- Deutsche UI-Texte, Englisch im Code
## Error Handling
- Log + Rückgabe (bestehend); für neue komplexe Logik optional BusinessException
## Persistenz
- Neue Entity: id == null vor persist
- refresh(entity) nutzen um Lazy Collections zu initialisieren
## Transaktionen
- Schreibmethoden: @Transactional (oder rely auf EJB Container)
## Performance
- Sammeloperationen: saveAll(Collection<T>)
## UI
- PrimeFaces Dialoge schließen mit closeDialogs
- Negative IDs in Listen bis Sammelspeichern
## PDF
- Neue Funktionen nur mit iText7 API
## Tests (Empfehlung)
- CRUD Manager Tests
- Klon & Fragebogen Zuordnung
## Anti-Pattern
- Logik nicht direkt im Controller wenn generell wiederverwendbar
- Keine duplizierten Query Strings -> Named Queries
---
Aktualisiert: 2025-10-20
+46
View File
@@ -0,0 +1,46 @@
# Error Handling Instructions
Aktualisiert: 2025-10-20
## Aktueller Zustand
- Fehler werden in Managern primär über `LOGGER.error(e)` geloggt.
- Rückgabe bool (true/false) signalisiert Erfolg/Misserfolg.
- Keine differenzierte Fehlerklassifikation (Business vs. System).
## Ziele
- Konsistente Behandlung & klare Trennung der Fehlerarten.
- Verbesserte Diagnose für Nutzer & Logs.
## Kategorien
1. Validation Errors (Bean Validation zukünftig) -> Nutzerfeedback.
2. Business Rule Violations -> eigene Exception (z.B. `BusinessException`).
3. System Errors (DB Down, Hibernate Exceptions) -> Logging + generische Fehlermeldung.
## Kurzfristige Empfehlungen
- Bei allen catch-Blöcken: `LOGGER.error("<Kontext>", e)` statt nur `LOGGER.error(e)`.
- Controller: Nach boolean false -> `errorMessage()` anzeigen.
## Einführung BusinessException (geplant)
- Checked oder Runtime? Vorschlag: Runtime zur vereinfachten Nutzung.
- Manager Methoden können `throw new BusinessException("Message")` statt false.
- Controller fängt BusinessException und zeigt spezifische Nachricht.
## Log Format
- Kontext + Entity-ID + Operation.
Beispiel: `LOGGER.error("Failed to persist SecurityArea id={} name={}", area.getId(), area.getName(), e);`
## Edge Cases
- Null Übergaben -> früh validieren & BusinessException werfen (später) / false zurückgeben (jetzt).
- Sammeloperation: Teilfehler -> aktuell Abort bei erstem Fehler. Optional Sammeln & Aggregatfehler.
## Verbesserungen
- Central Exception Mapper (JSF PhaseListener / CDI Interceptor).
- Korrelation IDs in Logs (Request ID, User ID).
## Generator Leitplanken
- Logging immer, auch bei ignorable Exceptions.
- Keine System.out Nutzung.
- Fehler nicht stillschweigend verschlucken (mindestens loggen).
---
+33
View File
@@ -0,0 +1,33 @@
# Extend Project Instructions
## Pattern
Entity -> Manager -> Controller -> XHTML -> Navigation
## Steps (Template)
1. Entity: @Entity extends AbstractEntity
2. Manager: @Stateless extends AbstractManager<Entity>
3. Controller: @Named + Scope extends AbstractController<Entity>
4. UI: xhtml mit #{controller}
5. Tests: CRUD + Spezialmethoden
## Fake IDs
- Neue Objekte in Collections: negative ID (createFakeID)
- Vor Persist: setId(null)
## Klonen
- Quelle laden & initialisieren
- Copy-Konstruktor
- Child IDs null
## Checklist
- [ ] Named Queries falls benötigt
- [ ] Logging bei Fehlern
- [ ] @Transactional bei Schreibmethoden
- [ ] Keine System.out
## Common Pitfalls
- LazyInitializationException -> refresh
- Vergessen negative IDs zurückzusetzen -> Persist fehlschlägt
---
Aktualisiert: 2025-10-20
+31
View File
@@ -0,0 +1,31 @@
# General Project Instructions
## Quick Facts
- Java EE 8 (javax) / Java 11 / WAR
- JSF + PrimeFaces + PrimeFlex
- Persistence Unit: pu_person
- Logging: Log4j2
## Build
mvn clean package -> target/mss-1.0-SNAPSHOT.war
## Core Patterns
- Manager: CRUD + Fachmethoden (extends AbstractManager)
- Controller: UI State + Messages + PDF (extends AbstractController)
- Negative IDs für temporäre Objekte
## PDF
- iText7 bevorzugen; Legacy iText5 entfernen später
## Improvements Roadmap
- Vereinheitlichte Exception Strategie
- Test Suite aufbauen
- Migration nach Jakarta EE (Namespace Wechsel)
## AI Generation Hints
- Halte Signaturen stabil
- Keine neuen Frameworks
- Initialisiere Lazy Collections vor Nutzung
---
Aktualisiert: 2025-10-20
+53
View File
@@ -0,0 +1,53 @@
# Index Instructions
Aktualisiert: 2025-10-20
Zentraler Überblick über alle *.instructions.md Dateien im Ordner `.github` für automatische Nutzung.
## Übersicht Bestehend
- Architektur: `architecture.instructions.md`
- Coding Guidelines: `coding_guidelines.instructions.md`
- Domain (Security Area): `security_area_domain.instructions.md`
- Fragebogen Workflow: `questionnaire_workflow.instructions.md`
- Projekt Erweiterung: `extend_project.instructions.md`
- Refresh & Fake-ID Mechanismus: `refresh_fake_id.instructions.md`
- Allgemeine Projektinfo: `general_project.instructions.md`
- AI Kontext / Generatorhinweise: `ai_context.instructions.md`
## Neue Spezial-Themen
- Persistence Layer: `persistence.instructions.md`
- PDF Generierung (iText7): `pdf_generation.instructions.md`
- Klon-Strategien: `cloning.instructions.md`
- Fehler & Logging: `error_handling.instructions.md`
- Test-Strategie: `testing_strategy.instructions.md`
- Transaktionen: `transactions.instructions.md`
- Manager/Controller Muster: `manager_controller_pattern.instructions.md`
## Verwendung (Automatisierung)
1. Start: `general_project.instructions.md` + `architecture.instructions.md` lesen.
2. Bei neuen Entities: `extend_project.instructions.md` + `persistence.instructions.md`.
3. Bei UI/Business Verkettung: `manager_controller_pattern.instructions.md`.
4. Für Fragebogenfunktionen: `questionnaire_workflow.instructions.md` + `security_area_domain.instructions.md`.
5. Für temporäre IDs & Refresh: `refresh_fake_id.instructions.md`.
6. Für PDF Features: `pdf_generation.instructions.md`.
7. Für Klon-Operationen: `cloning.instructions.md`.
8. Für Fehlerstrategie: `error_handling.instructions.md`.
9. Für Transaktionsregeln: `transactions.instructions.md`.
10. Für Qualitätsstil: `coding_guidelines.instructions.md`.
## Priorität bei Unklarheiten
1. `general_project.instructions.md`
2. `architecture.instructions.md`
3. `coding_guidelines.instructions.md`
4. Spezialthema betreffende Datei
## Pflegehinweise
- Beim Ändern von Basisklassen (AbstractManager / AbstractController / AbstractEntity) entsprechende Dateien aktualisieren.
- Tippfehler Methode `refrehSelected()` bei Umbenennung in Code auch in `refresh_fake_id.instructions.md` und `architecture.instructions.md` anpassen.
- Neue fachliche Domains erhalten eigene `<domain>.instructions.md` Datei mit Operations-, Entity- und Edge Case Liste.
## Roadmap Dokumentation
- Nach Einführung eines Exception Layers: `error_handling.instructions.md` erweitern.
- Nach Migration zu Jakarta: Alle Dateien Namespace Hinweis aktualisieren.
---
+102
View File
@@ -0,0 +1,102 @@
# Manager/Controller Pattern Instructions
Aktualisiert: 2025-10-20
## Ziele
Klare Trennung zwischen UI-Zustand (Controller) und Geschäftslogik/Persistenz (Manager).
## Verantwortlichkeiten
Controller:
- Zustände: selected, created, entities.
- UI Nachrichten (FacesMessage).
- Dialogsteuerung (PrimeFaces Widgets schließen).
- Hilfsfunktionen (PDF, Fake-ID-Erzeugung).
Manager:
- CRUD Operationen (create, edit, save, saveAll, remove, removeAllIn, find, findAll).
- Fachspezifische Queries / Reload.
- Fehlerlogging.
## Interaktion
- Controller ruft Manager.save / saveAll auf für Persistenz.
- Nach Änderungen: Controller.refrehSelected() (Tippfehler) -> aktualisiert ausgewähltes Objekt.
- Kein direkter EntityManager Zugriff im Controller.
## Fake-ID Ablauf
1. Controller erzeugt neue Entität (id == null).
2. Falls Sammlung benötigt: setzt negative ID über createFakeID.
3. Bei Save: Manager erkennt id < 0 (nach vorherigem Nullsetzen) -> persist.
## Methoden-Namenskonventionen
- Manager: Verb + Domänenobjekt (addQuestionnaireToSecurityArea, removeQuestionnaireFromSecurityArea).
- Controller: UI Aktionen (saveSelected, createNew, openDialog, closeDialogs).
## Edge Cases
- selected == null bei refresh -> no-op.
- entities Liste leer -> UI Tabelle zeigt keine Einträge; Null vermeiden (immer leere Liste).
## Messaging
- Erfolg: `successMessage()`; Fehler: `errorMessage()`.
- Spezifische Warnungen über `sendWarnMessage`.
## Verbesserungen
- Umbenennung `refrehSelected()` -> `refreshSelected()` in Basisklasse + alle Verwendungen.
- Einführung eines BasePDFController oder Utility zur Auslagerung PDF Logik.
## Generator Leitplanken
- Zusätzliche Logik (berechnete Felder, Validierungen) zuerst im Manager statt im Controller (besser testbar, wiederverwendbar).
- Controller schlank halten: keine komplexe Businessregeln.
---
# Persistence Instructions
Aktualisiert: 2025-10-20
## Ziele
Konsistente JPA Nutzung (Java EE 8, Hibernate Provider) mit klaren Regeln für IDs, Lazy Loading und Flush.
## Grundsätze
- Entities extend `AbstractEntity` (Long id, creationDate, changedDate, outdated Flag).
- Identity Generation: `@GeneratedValue(strategy = GenerationType.IDENTITY)` -> Kein manuelles Setzen positiver IDs.
- Equals/HashCode nur auf ID (Basis-Klasse bereitgestellt).
## ID & Fake-ID Handling
- Temporäre neue Objekte können negative IDs erhalten (Fake) zur UI-Differenzierung.
- Vor persist: if id != null && id < 0 -> `setId(null)` damit JPA eine echte ID generiert.
- Niemals persist mit negativer ID ausführen.
## Lebenszyklus
1. Konstruktor setzt creationDate & changedDate.
2. Bei Änderungen Fachlogik: changedDate aktualisieren (TODO: zentralisieren via EntityListener).
3. Persist -> flush direkt in `AbstractManager.save` / `saveAll`.
## Lazy Loading
- Vermeide direkte Iteration über nicht initialisierte Collections außerhalb Transaktion.
- Nutzung `AbstractManager.refresh(entity)` initialisiert das Entity (Hibernate.initialize(entity)).
- Für Collections eigene Reload-Methoden in spezialisierten Managern implementieren.
## Named Queries & Criteria
- Bevorzugt Criteria API für dynamische Filter.
- Häufig verwendete, statische Abfragen als `@NamedQuery` in der Entity definieren.
## Performance Hinweise
- `saveAll(Collection<T>)` nutzt einen Flush am Ende; reduziert DB Roundtrips.
- Bulk Delete oder Update lieber über JPQL statt Einzelloops (aktuell: removeAllIn loop; Optimierungspotential).
## Edge Cases
- `save(null)` => false (kein Fehlerwurf, Logging im Manager).
- Leere Collections in `saveAll` => true (no-op).
- `remove(entity)` mit `entity.getId()==null` => false; vorher persistieren oder ignorieren.
## Verbesserungs-Ideen
- EntityListener für Timestamps.
- Soft Delete (outdated Flag) statt physischem Löschen für Audit.
- Einführung eines Version-Feldes für Optimistic Locking.
## Generator Leitplanken
- Keine Änderung der ID-Strategie ohne umfassende Migration.
- Bei neuen Entities standardisierte Felder aus `AbstractEntity` nutzen.
- Collections initialisieren (z.B. `new ArrayList<>()`) im Entity-Konstruktor.
---
+46
View File
@@ -0,0 +1,46 @@
# PDF Generation Instructions
Aktualisiert: 2025-10-20
## Kontext
PDF-Erstellung erfolgt aktuell über Hilfsmethoden in `AbstractController` mittels iText7.
## Kern-Hilfsmethoden
- `loadCompanyLogo()` -> Lädt Logo aus LOGO_PATH.
- `generateSorroundingTable(String header, float maxWidth)` -> Einspaltige Rahmen-Tabelle mit Header.
- `generateInnerTable(Text header, boolean last, String... values)` -> 2-Spalten Tabelle mit alternierender Hintergrundfarbe.
- `generateInnerTable(Text header, int nrColumns, boolean last, String... values)` -> Generisch n-Spalten Tabelle.
- `addInnerCells(Table table, String name, String value, boolean isGray)` / Overload -> Fügt Datenzeilen hinzu.
- `addPagenumbers(Document document, String ticketNr, Image nextPagesCompanyLogo)` -> Fügt Seitenzahlen & Logo hinzu.
## Gestaltungsrichtlinien
- Fonts: Standard Helvetica / Bold (Konstanten `FONT_NORMAL`, `FONT_BOLD`).
- Schriftgrößen klein (8F Inhalte, 11F Header, 12F Hauptheader) für konsistente Layouts.
- Wechselnde Hintergrundfarbe (LIGHT_GRAY) zur besseren Lesbarkeit.
## Erweiterung
Neue Tabellen-/Layout-Funktionen:
1. Prüfen ob existierende Methoden erweiterbar statt neue Variante.
2. Konsistenz in Font & Spaltenbreiten wahren.
3. Kein Hardcode von absoluten Positionen außer bei Kopf-/Fußzeilen.
## Ressourcen Pfade
- LOGO_PATH statisch: `/rundata/logo.png`. Anpassungen zentral vornehmen.
## Fehlerhandhabung
- Aktuell wenige try/catch Blöcke; bei Erweiterung: Fehler loggen (`LOGGER.error(e)`) und Benutzer über Controller Messages informieren.
## Edge Cases
- Leere Werte -> `-/-` Platzhalter.
- Null Tabelleninstanz in addInnerCells -> early return.
## Verbesserungen
- Einführung eines PDFUtility Service zur Entkopplung vom Controller.
- Parameterobjekt für dynamische Tabellenkonfiguration (Spaltenbreiten, Farben, Größen).
## Generator Leitplanken
- iText7 API weiterverwenden; keine neuen PDF Libraries.
- Wiederverwendbare Logik nicht direkt im konkreten Controller implementieren -> Utility / Service.
---
+28
View File
@@ -0,0 +1,28 @@
# Questionnaire Workflow Instructions
## Add
areaManager.addQuestionnaireToSecurityArea(area, questionnaire)
- area ggf. re-laden
- Wrapper erzeugen
- Persist wrapper + merge area
- Rückgabe: aktualisierte Area
## Remove
areaManager.removeQuestionnaireFromSecurityArea(area, wrapper)
- area & wrapper re-laden
- Collection remove, em.remove(wrapper), em.merge(area)
## Available List
getAvailableQuestionnaires(area): SELECT q FROM Questionaire q ORDER BY q.name
- Filter: bereits zugeordnete Namen
## Edge Cases
- Null area/questionnaire -> Fehlermeldung
- Race condition -> nach Add/Remove refreshSelected()
## Verbesserungen
- ID statt Name für Filter
- Duplikatprüfung direkt im Manager
---
Aktualisiert: 2025-10-20
+25
View File
@@ -0,0 +1,25 @@
# Refresh & Fake ID Instructions
## Fake ID
- Negative Long Werte (<0) = temporär
- Sequenz: -1, -2, -3 ... (kleinste negative - 1)
- Erzeugung: AbstractController.createFakeID(Collection<E>)
## Persist
- Vor Speichern: if id < 0 -> setId(null)
- save/saveAll: id == null => persist, sonst merge
## Refresh
- AbstractController.refrehSelected() (Tippfehler) -> getManager().refresh(selected)
- AbstractManager.refresh(entity): if id == null -> save(entity); merge + Hibernate.initialize(entity)
## Best Practices
- Nach Add/Remove Child Collections refresh
- Beim Klonen zuerst Quelle laden
## Verbesserungen
- Methode umbenennen zu refreshSelected()
- JavaDoc für createFakeID
---
Aktualisiert: 2025-10-20
+39
View File
@@ -0,0 +1,39 @@
# Security Area Domain Instructions
## Entities
- SecurityArea
- SecurityDevice / DangerPoint / SwitchingDevice
- SecurityAreaQuestionnaire (Wrapper) + Questionaire
## Operations
- cloneArea(SecurityArea)
- addQuestionnaireToSecurityArea(area, questionnaire)
- removeQuestionnaireFromSecurityArea(area, wrapper)
- getAvailableQuestionnaires(area)
- reloadWithQuestionnaires(area)
## Workflow (Add Questionnaire)
1. Area laden (falls id > 0)
2. Wrapper erstellen & area setzen
3. Persist Wrapper, merge Area
4. Refresh im Controller
## Deletion Pattern
- Beziehungen lösen (Kinder area = null setzen)
- Kinder entfernen (Manager.removeAllIn)
- Area per Named Query löschen
## Edge Cases
- Duplicate questionnaire by name -> aktuell Filter per Name
- Verbesserung: Filter per ID
## Klonen
- Persistente Quelle re-laden, initialisieren
- Copy-Konstruktor & alle Child IDs auf null
## Verbesserungen
- CascadeSettings prüfen
- Bean Validation einsetzen
---
Aktualisiert: 2025-10-20
+49
View File
@@ -0,0 +1,49 @@
# Testing Strategy Instructions
Aktualisiert: 2025-10-20
## Ziele
Testabdeckung für kritische Pfade: CRUD, Clone, Fragebogen Zuordnung, Fake-ID Mechanismus.
## Testarten
1. Unit Tests (reine Logik, z.B. createFakeID, Klon Copy-Konstruktoren).
2. Integration Tests (Persistence + Manager Methoden gegen Test-DB). Möglich mit in-memory H2 + angepasster persistence.xml.
3. UI/Controller Smoke Tests (Optional, z.B. mit Selenium/Arquillian Graphene).
## Prioritäten
- AbstractManager.save / saveAll Edge Cases.
- remove / removeAllIn (Null, nicht persistierte Entities).
- createFakeID Sequenz (-1, -2, -3 ...).
- Fragebogen Add/Remove Workflow (Wrapper Persistenz, Filterliste).
- Klonen tiefer Objektgraph.
## Beispiel Unit Test Fälle
- createFakeID(null) => -1.
- createFakeID(leere Liste) => -1.
- createFakeID([id=-1]) => -2.
- createFakeID([id=-3, id=-1]) => -4.
## Integration Tests (CRUD)
- Persist neue Entity -> ID != null.
- Merge vorhandene Entity -> unverändert Fachfelder korrekt übernommen.
- saveAll mit gemischten (neue + vorhandene) -> alle persistent.
## Fehlerpfade
- save(null) -> false.
- remove(null) -> false.
- remove(entity ohne ID) -> false.
## Klon Tests
- Quelle & Klon dürfen nicht gleiche ID haben.
- Child Collections tief kopiert (Referenzen ungleich, Werte gleich).
## Tooling Vorschlag
- JUnit 5, Mockito für isolierte Tests von Controller-Hilfsmethoden.
- Testcontainers (Optional später) für realistischere DB.
## Generator Leitplanken
- Für neue Fachlogik minimal 1-2 Unit Tests + 1 Integration Test.
- Keine Abhängigkeit auf Produktionspfade in Unit Tests; Test-spezifische Testdaten-Builder.
---
+40
View File
@@ -0,0 +1,40 @@
# Transactions Instructions
Aktualisiert: 2025-10-20
## Kontext
Container-Managed Transaktionen (Java EE). Verwendung von `@Transactional` auf Manager-Methoden für Schreiboperationen.
## Grundsätze
- Jede persistierende Operation (create, edit, remove) innerhalb einer Transaktion.
- `save` und `saveAll` bereits mit `@Transactional` versehen.
- Leseoperationen können ohne Annotation auskommen (Default: kein Write-Lock nötig).
## Batch Operationen
- `saveAll(Collection<T>)`: Ein Transaktionskontext für gesamte Collection -> entweder komplett erfolgreich oder Abbruch beim Fehler.
- Optimierungspotential: Fehler sammeln, nicht sofort abbrechen.
## Refresh
- `refresh(entity)` führt merge aus; wenn `id == null` vorher persist -> bleibt innerhalb Transaktion falls aufgerufen durch `save`/`saveAll`.
## Remove
- `remove(entity)` ohne `@Transactional` in Basisklasse -> Empfehlung: Annotation hinzufügen in konkretem Manager wenn Delete-Fachlogik erweitert wird.
## Edge Cases
- Verschachtelte Aufrufe (save -> intern create/edit): Container handhabt Propagation (`REQUIRED`).
- LazyInitializationException vermeiden: innerhalb Transaktion initialisieren.
## Empfohlene Annotationen
- Zusätzliche fachliche Write-Methoden stets mit `@Transactional` versehen.
- Pure Read: Performancekritisch -> ggf. explizit `@Transactional(Transactional.TxType.SUPPORTS)` oder weglassen.
## Fehlerfall Verhalten
- Ungefangene RuntimeException -> Rollback durch Container.
- Aktuell Exceptions geloggt & boolean false -> verhindert Rollback. Verbesserung: BusinessException throw + Rollback.
## Generator Leitplanken
- Keine eigenen manuell geöffneten Transaktionen (kein `UserTransaction`).
- Konsistenz: Schreibmethoden annotieren, Leseoperationen nur bei Bedarf.
---
+21
View File
@@ -0,0 +1,21 @@
# Maven Build-Verzeichnis
target/
/target/
# IDE-spezifische Dateien
.idea/
.vscode/
*.iml
*.ipr
*.iws
# OS-spezifische Dateien
.DS_Store
Thumbs.db
# Logs
*.log
# Temporäre Dateien
*.tmp
*.temp
+88
View File
@@ -0,0 +1,88 @@
# mss-failsafe — Git History Archive
> **Why this file exists**
>
> `mss-failsafe` was developed in its own standalone Git repository (no remote) on
> Patrick's workstation. On **2026-06-13** it was consolidated into the `pi_mcps`
> monorepo under [`java/mss-failsafe/`](.) as the single canonical copy. The
> standalone repo's `.git` directory was removed during the flatten, so the original
> per-commit history below is preserved here for reference.
>
> The **flattened working tree** captured at consolidation = tip of `master`
> (`2a142b5`, 2025-10-04) **plus all uncommitted working-tree changes** that were in
> progress at that time (notably the `.github/*.instructions.md` AI-context files and
> `.gitignore` updates). This snapshot is the source of truth and the base for the
> planned upgraded rewrite with Work Lumen.
## Repository Facts (at time of archival)
| Property | Value |
|---|---|
| Standalone repo location | `~/pi_mcps/mss-failsafe/` (top-level, pre-consolidation) |
| New canonical location | `java/mss-failsafe/` (inside `pi_mcps` monorepo) |
| Default branch | `master` |
| Tip commit | `2a142b5` (2025-10-04) |
| Total commits (all branches) | 33 |
| First commit | `f2fa7b6` (2025-06-27) |
| Author | Patrick Plate |
| Remote | none (local-only repo) |
| Uncommitted changes at archival | 175 working-tree entries (preserved in the flatten) |
## Branches (at time of archival)
| Branch | Tip | Date | Note |
|---|---|---|---|
| `master` | `2a142b5` | 2025-10-04 | Default; newest committed state |
| `bugfix/protocol-creation-speed` | `2a142b5` | 2025-10-04 | Same tip as master |
| `bugfix/overview-pdf-counting` | `0226952` | 2025-09-25 | |
| `feature/zusammenfassung-pdf` | `7e2dd63` | 2025-09-17 | Contains `7e2dd63` not on master |
| `feature/all-checklist-at-once` | `7f68bbf` | 2025-09-13 | |
### Commits not reachable from `master`
| Hash | Date | Branch | Subject |
|---|---|---|---|
| `7e2dd63` | 2025-09-17 | `feature/zusammenfassung-pdf` | refactor(questionnaire): improve text handling in SecurityAreaQuestion |
| `b26b211` | 2025-09-15 | (dangling) | refactor: update UI text and logic for machine creation and editing |
## Full Commit Log (all branches, newest first)
| Hash | Date | Subject |
|---|---|---|
| `2a142b5` | 2025-10-04 | feat(ticket): optimize ticket fetching and indexing for protocol generation |
| `a28584b` | 2025-10-03 | feat(ticket): optimize protocol generation by reducing DB queries and enhancing ZIP creation logic |
| `0226952` | 2025-09-25 | feat(ticket): add alphabetical ordering for displayed lists and data tables |
| `06f1b0a` | 2025-09-25 | fix(ticket): handle null device roles in security device filtering |
| `5cba533` | 2025-09-17 | feat(ticket): enhance danger point and inspection data in overview protocol |
| `7e2dd63` | 2025-09-17 | refactor(questionnaire): improve text handling in SecurityAreaQuestion |
| `b26b211` | 2025-09-15 | refactor: update UI text and logic for machine creation and editing |
| `d535571` | 2025-09-15 | refactor(ticket): make DateTimeFormatter immutable in OverviewProtocolController |
| `593080e` | 2025-09-15 | refactor(ticket): remove unused imports in OverviewProtocolController |
| `44cb289` | 2025-09-15 | fix(ticket): correct typo in column header and reset flag in protocol generation |
| `1fd6bcf` | 2025-09-14 | feat(ticket): add overview protocol generation and integration |
| `7f68bbf` | 2025-09-13 | refactor(ticket): streamline PDF generation and file handling for machine protocols |
| `daeacc9` | 2025-09-13 | feat(ticket): add functionality to generate and download all machine protocols as ZIP |
| `0166206` | 2025-09-13 | feat(questionnaire): enhance UI and improve questionnaire management logic |
| `24da4a1` | 2025-08-29 | feat(questionnaire): improve questionnaire integration and UI enhancements |
| `913efbb` | 2025-08-29 | feat(questionnaire): enhance questionnaire handling with better UI and data loading |
| `b3782fc` | 2025-08-29 | feat(questionnaire): enhance question position management and text handling |
| `884cb80` | 2025-08-25 | fix(security-area): resolve lazy loading and eager collection conflict for questionnaires |
| `3fd6e2e` | 2025-08-24 | Admin: add System-Logs page and LogFileManager; update admin menu; set active RollingFile to /logs/application.log |
| `11d96cd` | 2025-08-16 | feat(admin): neue Admin-Views (password reset, user management) und Controller |
| `6238521` | 2025-07-26 | Refactor: UserRoleValidationManager als Startup-Service konfiguriert (@Singleton/@Startup, @PostConstruct validateRolesOnStartup) |
| `eeb329d` | 2025-07-26 | Feature: UserRoleValidationManager für automatische Rollenkorrektur |
| `2d72946` | 2025-07-26 | Dokumentation: Detaillierte Kommentare zur Person-Entität hinzugefügt |
| `66bb699` | 2025-07-20 | Implement hierarchical user role assignment system (UserRoleAssignmentHelper) |
| `8ee06b4` | 2025-07-20 | Add comprehensive JavaDoc comments to model classes |
| `3438bcb` | 2025-07-20 | Remove target directory from repository and improve .gitignore |
| `ed70e9f` | 2025-07-15 | Update .gitignore to include an empty /target/ directory |
| `7072410` | 2025-07-03 | Improve UI loading experience and update controller logic |
| `0d9c1fa` | 2025-06-27 | Update multiple controller classes across various modules |
| `0ab4495` | 2025-06-27 | Refactor controllers to remove session dependency and improve transaction management; add .gitignore for target directory |
| `f2fa7b6` | 2025-06-27 | Add initial project structure and configuration files |
---
*Archived 2026-06-13 during the mss-failsafe consolidation into `pi_mcps`. The full
binary Git history of the original standalone repo was not migrated — only this
human-readable log plus the final flattened working tree.*
@@ -0,0 +1,199 @@
# Questionnaires für SecurityArea - Implementierungsplan
## Übersicht
Implementierung der Funktionalität zur Hinzufügung von Fragebögen (Questionnaires) zu SecurityArea-Entitäten in den Basisdaten. Dies ermöglicht es, Fragebögen bereits bei der Erstellung von Sicherheitsbereichen zu hinterlegen, anstatt erst bei der Ticket-Erstellung.
## Hintergrund
- **Aktueller Stand**: Questionnaires werden nur zu TicketSecurityArea hinzugefügt
- **Neues Ziel**: Questionnaires sollen auch zu SecurityArea (Basisdaten) hinzugefügt werden können
- **Grund**: Verbesserung des Workflows entsprechend Kundenwunsch
## Schritt-für-Schritt Implementierung
### 1. Datenbankmodell erweitern
#### 1.1 SecurityArea Entität anpassen
- **Datei**: `src/main/java/model/securityarea/SecurityArea.java`
- **Aufgabe**:
- Neue Beziehung zu Questionnaires hinzufügen
- `@OneToMany` Mapping für `SecurityAreaQuestionnaire` implementieren
- Ähnlich wie bei TicketSecurityArea → SecurityAreaQuestionnaire
#### 1.2 Neue Entität: SecurityAreaQuestionnaire
- **Datei**: `src/main/java/model/securityarea/SecurityAreaQuestionnaire.java` (neu erstellen)
- **Aufgabe**:
- Entität ähnlich zu `TicketSecurityAreaQuestionnaire` erstellen
- `@ManyToOne` Beziehung zu SecurityArea
- `@OneToMany` Beziehung zu SecurityAreaQuestion
- Konstruktor für Kopieren von Questionnaire → SecurityAreaQuestionnaire
#### 1.3 Neue Entität: SecurityAreaQuestion
- **Datei**: `src/main/java/model/securityarea/SecurityAreaQuestion.java` (neu erstellen)
- **Aufgabe**:
- Entität ähnlich zu `SecurityAreaQuestion` aus tickets package erstellen
- `@ManyToOne` Beziehung zu SecurityAreaQuestionnaire
- Alle notwendigen Felder für Fragen implementieren
### 2. Business Logic implementieren
#### 2.1 SecurityAreaManager erweitern
- **Datei**: `src/main/java/business/securityarea/SecurityAreaManager.java`
- **Aufgabe**:
- Methoden für Questionnaire-Management hinzufügen
- `addQuestionnaireToSecurityArea()`
- `removeQuestionnaireFromSecurityArea()`
- `getAvailableQuestionnaires()`
#### 2.2 QuestionnaireManager anpassen
- **Datei**: `src/main/java/business/questions/QuestionnaireManager.java`
- **Aufgabe**:
- Methoden für SecurityArea-Questionnaire Verknüpfung
- Validierung für Questionnaire-Zuordnung
### 3. Controller Layer erweitern
#### 3.1 SecurityAreaController anpassen
- **Datei**: `src/main/java/controller/securityarea/SecurityAreaController.java`
- **Aufgabe**:
- Properties für Questionnaire-Auswahl hinzufügen
- `selectedQuestionnaire`, `availableQuestionnaires`
- Methoden: `addQuestionnaireToArea()`, `removeQuestionnaireFromArea()`
- Integration in `save()` und `editSelected()` Methoden
#### 3.2 Neue Controller für SecurityAreaQuestionnaire
- **Datei**: `src/main/java/controller/securityarea/SecurityAreaQuestionnaireController.java` (optional)
- **Aufgabe**:
- Dedicated Controller für Questionnaire-Management
- Ähnlich zu bestehenden Questionnaire-Controllern
### 4. UI Implementation
#### 4.1 Hauptseite erweitern
- **Datei**: `src/main/webapp/resources/user/sec/create.xhtml`
- **Aufgabe**:
- Neue Sektion für Questionnaires in SecurityArea-Details hinzufügen
- Position: Nach den DangerPoints, vor dem Bottom-Bereich
- Accordion-Panel für Questionnaires ähnlich wie bei SecurityDevices
#### 4.2 Questionnaire-Management UI
- **Komponenten hinzufügen**:
- DataTable für angehängte Questionnaires
- Buttons: "Fragebogen hinzufügen", "Bearbeiten", "Entfernen"
- Dialog für Questionnaire-Auswahl
- Dialog für Questionnaire-Bearbeitung
#### 4.3 Dialog-Implementierung
- **Neue Dialogs in create.xhtml**:
- `dlgAddQuestionnaire`: Auswahl verfügbarer Questionnaires
- `dlgEditQuestionnaire`: Bearbeitung der Questions
- Ähnlich zu bestehenden Device/DangerPoint Dialogs
### 5. Integration und Workflow
#### 5.1 Ticket-Erstellung anpassen
- **Aufgabe**: Bei Ticket-Erstellung Questionnaires von SecurityArea automatisch kopieren
- **Dateien**:
- Ticket-Erstellungs-Controller
- TicketSecurityArea-Business-Logic
#### 5.2 Copy/Clone Funktionalität
- **Aufgabe**: Beim Kopieren von SecurityAreas auch Questionnaires mitkopieren
- **Betroffene Methoden**: `cloneToSelectedMachine()` in SecurityAreaController
### 6. UI/UX Details
#### 6.1 SecurityArea-Karte erweitern
```html
<!-- Nach DangerPoints Accordion hinzufügen -->
<div class="p-col-12">
<p:accordionPanel value="#{securityAreaController.selected.questionnaires}" var="questionnaire" activeIndex="#">
<p:tab title="Fragebogen: #{questionnaire.name}">
<!-- Questionnaire Details und Questions anzeigen -->
</p:tab>
</p:accordionPanel>
</div>
```
#### 6.2 Questionnaire-Management Buttons
- In das "Mehr"-Menü (dynaButton) integrieren
- Neue Menüpunkte: "Fragebogen hinzufügen", "Fragebögen verwalten"
### 7. Testing und Validierung
#### 7.1 Unit Tests
- **Neue Test-Klassen**:
- `SecurityAreaQuestionnaireTest`
- `SecurityAreaQuestionTest`
- `SecurityAreaManagerTest` (erweitern)
#### 7.2 Integration Tests
- Questionnaire-Zuordnung zu SecurityArea
- Kopieren von Questionnaires bei Ticket-Erstellung
- UI-Workflow Tests
#### 7.3 Datenbank-Migration
- **Aufgabe**: SQL-Scripts für neue Tabellen erstellen
- Tables: `SECURITY_AREA_QUESTIONNAIRE`, `SECURITY_AREA_QUESTION`
- Foreign Key Constraints definieren
## Reihenfolge der Implementierung
1. **Phase 1**: Datenbankmodell (SecurityAreaQuestionnaire, SecurityAreaQuestion)
2. **Phase 2**: Business Logic (Manager-Erweiterungen)
3. **Phase 3**: Controller Layer (SecurityAreaController erweitern)
4. **Phase 4**: UI Implementation (create.xhtml erweitern)
5. **Phase 5**: Integration (Ticket-Erstellung anpassen)
6. **Phase 6**: Testing und Finalisierung
## Wichtige Überlegungen
### Datenmodell-Konsistenz
- Questionnaires in SecurityArea müssen kompatibel zu TicketSecurityArea sein
- Beim Ticket-Erstellen: SecurityArea-Questionnaires → TicketSecurityArea kopieren
### UI-Konsistenz
- Gleiche Bedienung wie bei SecurityDevices/DangerPoints
- Accordion-Panel für übersichtliche Darstellung
- Standard CRUD-Operationen (Create, Read, Update, Delete)
### Performance
- Lazy Loading für Questionnaires implementieren
- Effizienter Datentransfer bei Questionnaire-Kopierung
## Dependencies
### Neue Dateien zu erstellen:
- `model/securityarea/SecurityAreaQuestionnaire.java`
- `model/securityarea/SecurityAreaQuestion.java`
- Controller-Erweiterungen
- UI-Erweiterungen in create.xhtml
### Bestehende Dateien zu modifizieren:
- `model/securityarea/SecurityArea.java`
- `controller/securityarea/SecurityAreaController.java`
- `business/securityarea/SecurityAreaManager.java`
- `resources/user/sec/create.xhtml`
## Zeitschätzung
- **Phase 1-2**: 2-3 Tage (Backend)
- **Phase 3-4**: 3-4 Tage (Controller + UI)
- **Phase 5-6**: 2-3 Tage (Integration + Testing)
- **Gesamt**: ~8-10 Arbeitstage
## Risiken und Mitigationen
### Datenbankmigrationen
- **Risiko**: Bestehende Daten könnten beeinträchtigt werden
- **Mitigation**: Backup vor Migration, schrittweise Einführung
### UI-Komplexität
- **Risiko**: UI wird zu überladen
- **Mitigation**: Accordion-Panel verwenden, ähnlich zu bestehenden Komponenten
### Performance
- **Risiko**: Laden von vielen Questionnaires könnte langsam werden
- **Mitigation**: Lazy Loading, Paging implementieren
---
**Nächste Schritte**: Mit Phase 1 (Datenbankmodell) beginnen und die SecurityAreaQuestionnaire Entität implementieren.
+64
View File
@@ -0,0 +1,64 @@
# AI Instruktionen für Code-Generierung
Ziel: Ein konsistenter Kontext für zukünftige automatische Ergänzungen.
## Projekt-Kurzprofil
- Typ: Java EE 8 (javax), WAR, JSF + PrimeFaces, Hibernate JPA.
- Java Version: 11 (Compiler Plugin).
- Schichten: Model (Entities), Business (Manager), Controller (JSF Beans), View (XHTML).
## Wichtige Basisklassen
- `AbstractEntity`: Basisklasse aller Entities (enthält ID Details nicht gezeigt, aber zentral).
- `AbstractManager<T>`: Generisches CRUD mit `save`, `saveAll`, etc.
- `AbstractController<E>`: UI State & Utilities.
## Konventionen (Kurz)
- Neue Entities: extend `AbstractEntity`, Named Queries definieren.
- Neue Manager: `@Stateless`, extends `AbstractManager<Entity>`, implementiert `getEntityManager()`.
- Neue Controller: `@Named`, Scope Annotation (`@ViewScoped` etc.), extends `AbstractController<Entity>`, implementiert `getManager()`.
- Temporäre (nicht persistierte) Objekte: negative ID (Fake) bis finalem Speichern.
## CRUD Muster (Beispiel)
```java
@Stateless
public class ExampleEntityManager extends AbstractManager<ExampleEntity> {
@PersistenceContext(name = "pu_person") EntityManager em;
public ExampleEntityManager(){ super(ExampleEntity.class); }
@Override protected EntityManager getEntityManager(){ return em; }
}
```
## Typische Aufgaben für Generierung
1. Neue Domain + Entity + Manager + Controller + XHTML.
2. PDF-Ausgabe Erweiterung.
3. Batch-Speichern mehrerer neuer Entities.
4. Klon-Operationen: Copy-Konstruktor nutzen, Child-IDs auf `null` setzen, Referenzen neu knüpfen.
5. Fragebogen-Workflow: add/remove (siehe `QUESTIONNAIRE_WORKFLOW.md`).
## Qualitätssicherung
- Nach Code-Erzeugung: Prüfe Kompilierung (mvn -q test / package).
- Sicherstellen: Keine direkten System.out Prints in Produktionscode.
- Logging: `LOGGER.error(e)` bei Exceptions.
## Häufige Edge Cases
- Null Checks vor Persist/Remove.
- Negative ID Objekte dürfen nicht direkt gelöscht (erst persistieren oder aus Collection entfernen).
- Lazy Collections müssen initialisiert vor Iteration (via `refresh` oder `Hibernate.initialize`).
## Verbesserungsvorschläge (safe additions)
- Service Layer Einführen (wenn Logik Manager übersteigt).
- Bean Validation (@NotNull, @Size) auf Entities.
- Einheitliche Exception Klasse.
## Generierungs-Präferenzen
- Bevorzugt vorhandene Muster exakt replizieren.
- Keine neuen Frameworks ohne Bedarf.
- Code kommentieren nur bei komplexer Logik.
## Anti-Pattern vermeiden
- Business Logik direkt im Controller.
- Duplizierte Query Strings ohne Named Query.
---
Letzte Aktualisierung: 2025-10-20
+63
View File
@@ -0,0 +1,63 @@
# Architekturübersicht
## Layer
1. Präsentation: JSF 2.3 + PrimeFaces 11 (XHTML in `webapp/`).
2. Controller Layer: JSF Managed Beans (CDI `@Named`, Scopes) koordiniert UI → Business.
3. Business Layer: Stateless EJB Manager (`business.*Manager`) kapselt Datenzugriff + Fachlogik.
4. Persistenz Layer: JPA (Javax) + Hibernate Provider. Persistence Context Name: `pu_person`.
5. Ressourcen: `src/main/resources` für Log4j2, statische Texte, Checklisten.
## Zentrale Basisklassen
### AbstractManager<T extends AbstractEntity>
- Generisches CRUD: `save`, `saveAll`, `create`, `edit`, `remove`, `refresh`, `find`, `findAll`, `count`.
- Flush nach Persist/Merge (stellt zeitnah DB-Konsistenz sicher).
- Fehlerbehandlung: try/catch + Logging (Verbesserungspotential: Konsistente Exception).
### AbstractController<ENT extends AbstractEntity>
- UI State: `selected`, `created`, `entities`.
- Utility: Faces Messages, PDF Hilfsmethoden, Fake-ID Generator für neue Entities vor Persist.
- `refrehSelected()`: Re-merge & initialize Lazy Collections.
## Entity Lebenszyklus (UI Sicht)
1. Nutzer erstellt neues Objekt → Controller vergibt Fake-ID (negativ) mittels `createFakeID(Collection<ENT>)`.
2. Objekt wird in Listen angezeigt, kann editiert werden bevor persistiert.
3. Beim Speichern werden alle mit `id < 0` auf `null` gesetzt; `AbstractManager.saveAll()` persistiert.
4. Nach Persist: DB generiert positive ID.
## Sicherheitsbereich (SecurityArea)
- Enthält Listen: `SecurityDevices`, `DangerPoints`, `SwitchingDevices`, `Questionnaires`.
- Manager-Methoden: `cloneArea`, add/remove Questionnaire, `reloadWithQuestionnaires`.
- Klonen: Erst DB laden (falls persistent), dann Kopie via Copy-Konstruktor `new SecurityArea(area)`.
## Fragebogen-Zuordnung
- Hinzufügen: `SecurityAreaManager.addQuestionnaireToSecurityArea` erzeugt `SecurityAreaQuestionnaire` Wrapper (assoziative Entity) & persistiert.
- Entfernen: Entities werden aus Sammlung entfernt und via `em.remove(questionnaire)` gelöscht.
- Verfügbare Fragebögen: Alle `Questionaire` minus bereits zugeordnete (Filter per Namen potentielles Verbesserungspotential: Verwendung IDs statt Name).
## Transaktionen
- Methoden mit Schreiboperationen annotiert `@Transactional` (EJB Container verwaltet JTA). In `AbstractManager` ebenfalls.
## Logging
- Log4j2 überall via `LogManager.getLogger(...)`. Konfiguration: `log4j2.xml`.
## PDF Generierung
- `AbstractController` Hilfsmethoden zur Tabellen-Erstellung (iText7) + gemischte Nutzung iText5 (itextpdf 5.5.13) Migration empfohlen.
## Erweiterbarkeit
- Neue Fachbereiche folgen Pattern: Entity → Manager → Controller → UI.
- Reusable generische Methoden vermeiden Duplikate (Beispiel: `saveAll`, `refresh`).
## Bekannte technische Schulden
- Mischung iText5 & iText7.
- Fehlerbehandlung inkonsistent (bool Rückgaben + Logging).
- Kein einheitlicher DTO Layer Controller arbeitet direkt auf Entities (Risk: Lazy Loading im View).
- Wenige Tests im `test/` Verzeichnis.
## Ideen für Refactoring
- Einführung Service Layer (falls Business Logik komplexer wird) zw. Controller und Manager.
- Exceptions mit Custom Runtime (`BusinessException`) statt stiller bool False.
- Verwendung Criteria / NamedQueries für Wiederverwendbarkeit (z.Z. direkte Query Strings in Manager).
---
Aktualisiert: 2025-10-20
+61
View File
@@ -0,0 +1,61 @@
# Coding Guidelines
## Allgemein
- Sprache: Deutsch in UI-Messages, Englisch im Code (Klassennamen etc.).
- Einrückung: 4 Spaces (NetBeans Standard). Keine Tab-Mischung.
- Zeilenlänge: Empfehlung max. 140 Zeichen.
- Vermeide überflüssige System.out.println nutze Logger.
## Packages
- `business.<domain>` für Manager/Logik.
- `controller.<domain>` für JSF Backing Beans.
- `model.<domain>` für Entities/Enums.
## Benennung
- Manager endet auf `Manager` (CRUD + Fachlogik).
- Controller endet auf `Controller`.
- Entities nutzen Substantive singular (`SecurityArea`, `DangerPoint`).
- Enums nutzen PascalCase Konstanten (`APPROACH_SPEED`, hier bereits gemischt beibehalten vorhandene Fälle, Konsistenz bei neuen).
## Fehlerbehandlung
- Aktuell: Logging + bool Rückgabe. Bei neuen komplexen Methoden: Ziehe eigene Exceptions in Betracht (`BusinessException`).
- Niemals stack trace verlieren immer loggen. Falls Benutzerfeedback nötig → Message über Controller.
## Persistenz
- Vor Persist neuer Entity: ID muss `null` sein (oder negativ Fake-ID nur temporär). Setze beim finalen Speichern negative IDs auf `null`.
- Verwende `AbstractManager.refresh(entity)` um Lazy Collections zu initialisieren.
## Transaktionen
- Schreibmethoden erhalten `@Transactional`. Beim EJB Stateless reicht oft Container-Transaktion; Annotation verstärkt Klarheit.
## Performance
- Sammel-Speicheroperationen bevorzugt `saveAll(Collection<T>)` statt Schleifen mit einzelnen Flushes.
- Beim Klonen großer Objektgraphen prüfen: Nur notwendige Collections initialisieren.
## UI / JSF
- Vermeide direkte Änderungen an listengebundenen Collections ohne Aktualisierung des Backing Beans (PrimeFaces kann sonst nicht updaten).
- Nutze klare Dialog-Helper (closeDialogs) statt roher JavaScript Strings.
## PDF
- Konsistenz: Verwende iText7 API für neue Funktionen. Markiere Altcode (iText5) für spätere Entfernung.
## Sicherheit
- Keine sensiblen Daten in Logs.
- Prüfe vor Löschaktionen, dass referenzielle Integrität gewährleistet (vor Entfernen Beziehungen lösen, wie im `deleteSelected()` umgesetzt).
## Tests (Empfehlung)
- JUnit + Arquillian für EJB/Entity Tests.
- Test-Namensschema: `<ClassName>Test`.
- Mindestens: CRUD, Klonen, Fragebogen hinzufügen/entfernen.
## Kommentar-Stil
- Klassenheader: Kurze Beschreibung Funktion/Zweck.
- Methoden: JavaDoc nur bei komplexer Logik / öffentlich verwendeten APIs.
## Anti-Pattern vermeiden
- "God Controller" trenne Verantwortlichkeiten (nicht alles in einem Controller ansammeln).
- Direkte UI-Logik im Manager vermeiden.
---
Aktualisiert: 2025-10-20
+72
View File
@@ -0,0 +1,72 @@
# How-To: Projekt erweitern
## Neuer Fachbereich (Beispiel: InspectionReport)
### 1. Entity anlegen
- Paket: `model.report`.
- Klasse: `InspectionReport extends AbstractEntity`.
- Felder: `date`, `inspector`, `machine`, `remarks`.
- Named Queries definieren (z.B. `FIND_BY_MACHINE`).
### 2. Manager
```java
@Stateless
@Named
public class InspectionReportManager extends AbstractManager<InspectionReport> {
@PersistenceContext(name = "pu_person")
EntityManager em;
public InspectionReportManager() { super(InspectionReport.class); }
@Override protected EntityManager getEntityManager() { return em; }
// Fachmethoden: findByMachine(Long id)
}
```
### 3. Controller
```java
@ViewScoped
@Named
public class InspectionReportController extends AbstractController<InspectionReport> {
@EJB InspectionReportManager reportManager;
@Inject MachineController machineController;
public InspectionReportController() { setSelected(new InspectionReport()); setCreated(new InspectionReport()); }
@Override protected AbstractManager<InspectionReport> getManager() { return reportManager; }
@Override public void clearEntries() { setSelected(new InspectionReport()); setCreated(new InspectionReport()); getEntities().clear(); }
public void saveReport(){ reportManager.save(getSelected()); successMessage(); }
}
```
### 4. UI Seite
- Pfad: `webapp/report/inspection.xhtml`.
- Binding: `#{inspectionReportController}`.
- Komponenten: Formular für Felder + Speichern Button.
### 5. Navigation
- Menüeintrag in globaler Navigationsstruktur (Tree oder Topbar) analog `createMachineMenu()` Ansatz.
### 6. Tests
- Persistenz Test: Speichern + Laden.
- Manager Fachmethode Test.
## Erweiterung vorhandener Funktionalität
- Beispiel: Neue PDF Sektion → Ergänze Hilfsmethode in `AbstractController` (sofern allgemein). Falls spezifisch für eine Domäne, eher Hilfsklasse im Domain-Paket.
## Konsistenz-Checkliste
- [ ] Entity extends `AbstractEntity`
- [ ] Manager extends `AbstractManager`
- [ ] Controller extends `AbstractController`
- [ ] Negative IDs für neue Objekte vor Persist (falls in Listen)
- [ ] Internationale Zeichen (UTF-8) POM setzt Encoding
- [ ] Logging bei Fehlern
## Deployment Hinweise
- Sicherstellen, dass neue Named Queries beim Serverstart verfügbar (Entity korrekt gescannt).
- Falls neue Ressourcen (Logos, Templates) → in `resources` pflegen.
## Typische Stolpersteine
- LazyInitializationException: Lösung `refresh(entity)` oder explizite Initialisierung im Manager.
- Doppelte Referenzen beim Klonen: IDs auf `null` setzen.
- Fehlende Transaktion: Sicherstellen `@Transactional` oder EJB Standard.
---
Aktualisiert: 2025-10-20
+52
View File
@@ -0,0 +1,52 @@
# Workflow: Fragebögen in Sicherheitsbereichen
## Ziel
Zuordnung strukturiert erfassbarer Fragebögen (`Questionaire`) zu einem `SecurityArea` via `SecurityAreaQuestionnaire`.
## Beteiligte Klassen
- `SecurityAreaController` UI Aktionen (add/remove, refresh).
- `SecurityAreaManager` Persistenzoperationen (add/remove/reload, Verfügbarkeitsliste).
- `SecurityAreaQuestionnaire` Assoziative Entity (enthält Name / ID des Fragebogens + Bezug zum Schutzbereich).
- `QuestionaireManager` (nicht gezeigt) Verwaltung aller Fragebögen.
## Hinzufügen Ablauf
1. Nutzer wählt Schutzbereich + Fragebogen im Dialog.
2. Controller ruft `securityAreaManager.addQuestionnaireToSecurityArea(selectedArea, selectedQuestionnaire)`.
3. Manager:
- Lädt `area` (falls persistent) neu per `em.find`.
- Erzeugt neues `SecurityAreaQuestionnaire` Objekt.
- Setzt Relation (wrapper.setArea(area)).
- Persistiert Wrapper, merged Area.
4. Controller: `refrehSelected()` (Merge + Initialize Lazy Collections), zeigt Erfolgsmeldung.
## Entfernen Ablauf
1. Nutzer wählt zugeordneten Fragebogen (Wrapper-Objekt).
2. Controller ruft `securityAreaManager.removeQuestionnaireFromSecurityArea(area, wrapper)`.
3. Manager lädt Entities (falls notwendig), entfernt aus Collection, `em.remove(wrapper)`, `em.merge(area)`.
4. Controller aktualisiert Verfügbare Liste.
## Verfügbare Fragebögen
- Abfrage aller Fragebögen: `SELECT q FROM Questionaire q ORDER BY q.name`.
- Filter: Namen bereits zugeordneter Wrapper (Verbesserung: Filter per ID zur Sicherheit gegen Namensduplikate).
## Edge Cases
- Bereich / Fragebogen null: Controller zeigt Fehlermeldung.
- Concurrent Änderung: Nach Persist immer Refresh durchführen.
- Doppelte Zuordnung: Filter verhindert erneute Anzeige; Manager könnte zusätzlich prüfen (Collection enthält bereits Name).
## Verbesserungen
- Validierung auf Einzigartigkeit im Manager (statt nur UI Filter).
- Optimierte Fetch Strategie (JOIN FETCH) bei Reload.
- Nutzung eines Service zur Kapselung Geschäftslogik + Manager nur für CRUD.
## Beispiel Pseudocode (Hinzufügen)
```java
if (questionnaire != null && area != null) {
areaManager.addQuestionnaireToSecurityArea(area, questionnaire);
controller.refrehSelected();
}
```
---
Aktualisiert: 2025-10-20
+97
View File
@@ -0,0 +1,97 @@
# Mechanismus: Refresh & Fake-ID
## Problemstellung
Im UI werden häufig neue Objekte in Collections angezeigt, bevor sie persistiert sind. Diese benötigen eine temporäre Identifikation (ID) für Auswahl/Operationen, ohne den Datenbankzustand zu verfälschen.
## Fake-ID Strategie
- Negative Long Werte (< 0) kennzeichnen nicht persistierte Objekte.
- Erzeugung: `AbstractController.createFakeID(Collection<ENT>)`:
- Startwert -1.
- Falls bereits negative IDs existieren → Nimmt die kleinste negative und subtrahiert 1.
- Ergebnis: Sequenz -1, -2, -3 ... (absteigend).
## Persistieren
Vor finalem Speichern (z.B. `SecurityAreaController.save()`):
1. Alle Entities mit `id < 0``setId(null)`.
2. `AbstractManager.saveAll()` unterscheidet durch `entity.getId() == null` zwischen Persist und Merge.
3. Datenbank vergibt positive ID (Auto Increment / Sequence).
## Vorteile
- Klare Unterscheidung UI-temporär vs. persistent.
- Verhindert versehentliches Auslösen von Merge bei noch nicht existierenden DB Zeilen.
## Risiken
- Verwechslung negativ gesetzter IDs mit echten IDs (nicht möglich, da DB positive IDs generiert).
- Direkte Verwendung negativer IDs in DB-Operationen (vermeiden: Prüfen auf `id > 0` vor `em.find`).
## Refresh
- Methode `AbstractController.refrehSelected()` (Tippfehler im Namen, historisch) ruft `getManager().refresh(selected)`.
- `AbstractManager.refresh(entity)`:
- Falls ID null → `save(entity)` (persistiert neues Objekt).
- `merge` für Managed Zustand und `Hibernate.initialize(entity)` zur Lazy Init.
## Best Practices
- Nach komplexen Änderungen (Add/Remove Child Collections) Refresh durchführen wenn UI weitere Lazy Properties benötigt.
- Beim Klonen persistenter Objekte zuerst DB-Laden → danach Kopie erstellen.
## Potentielle Verbesserungen
- Korrektur Tippfehler `refrehSelected()``refreshSelected()` (Refactoring + Suchanpassungen).
- Kennzeichnung Fake-ID generierender Methoden mit JavaDoc für Klarheit.
---
Aktualisiert: 2025-10-20
# MSS Failsafe Developer Einstieg
Dieses Verzeichnis bündelt technische Instruktionsdateien zur schnelleren Einarbeitung und zur Unterstützung automatischer Code-Generierung.
## Quick Start
1. Java Version: Quell-/Ziellevel im POM: 11 (Property 1.8 ist historisch, der Compiler-Plugin setzt auf 11). Nutze lokal JDK 11.
2. Application Server: Java EE 8 kompatibel (z.B. Payara 5 / WildFly 20 / GlassFish 5). Dependencies `javax.*` statt `jakarta.*`.
3. Build:
```cmd
mvn clean package
```
Ergebnis: `target/mss-1.0-SNAPSHOT.war`.
4. Deployment: WAR in kompatiblen EE 8 Server einspielen. Konfiguriere Datenquelle `pu_person` (JPA Persistence Unit siehe `@PersistenceContext(name = "pu_person")`).
5. Logging: Log4j2 Konfiguration in `src/main/resources/log4j2.xml`.
6. Frontend: JSF 2.3 + PrimeFaces 11 + PrimeFlex 2.0.
## Wichtigste Schichten
- model: JPA Entities (`AbstractEntity` Basis enthält ID).
- business: `*Manager` Klassen (Stateless EJBs) kapseln CRUD + Fachlogik.
- controller: View/Request/Session Scoped JSF Backing Beans (Interaktion UI ↔ Business Layer).
- webapp: XHTML Seiten (JSF Components + PrimeFaces).
- resources: Text-/Konfigurationsdateien, Checklisten.
## Kern-Patterns
- Manager erben von `AbstractManager<T>` (generisches CRUD mit `save`, `saveAll`, `remove`, `refresh`).
- Controller erben von `AbstractController<E>` (Message Handling, Fake-ID-Erzeugung für neue (noch nicht persistierte) Entities, PDF Hilfen, Auswahlzustand `selected/created`).
- Negative IDs (< 0) werden als temporäre (noch nicht persistierte) Objekte verwendet wichtig bei UI-Listen vor Sammel-Speichern.
- Lazy Collections werden vor Nutzung mit `Hibernate.initialize(...)` initialisiert (Refresh/Reload Methoden).
## Erweiterung Schnellanleitung
1. Neue Entity anlegen (JPA @Entity, extends `AbstractEntity`).
2. Manager erstellen: `@Stateless`, extends `AbstractManager<YourEntity>`, implementiert `getEntityManager()`. Zusätzliche Named Queries in Entity definieren.
3. Controller erstellen: `@Named`, Scope festlegen (`@ViewScoped`, `@SessionScoped`, etc.), extends `AbstractController<YourEntity>`, injiziere Manager mit `@EJB`.
4. XHTML Seite/Fragment erstellen und Controller referenzieren (`#{yourController}`) + PrimeFaces Komponenten.
5. Tests (optional, derzeit kaum vorhanden) vorschlagen: Architektur-Test + Manager CRUD Test.
## Fragebögen / Sicherheitsbereiche
Ein ausführlicher Workflow liegt in `QUESTIONNAIRE_WORKFLOW.md` und `SECURITY_AREA_DOMAIN.md`.
## PDF-Erzeugung
- Verwendet iText (5.x + 7.x Module). Utilities liegen in `AbstractController` (Tabellen, Kopfzeilen, Seitennummern).
- Logo Pfad `LOGO_PATH = /rundata/logo.png` stelle sicher, dass Datei beim Deployment verfügbar ist.
## Automatisierte Tools / AI Hinweise
Siehe `AI_INSTRUCTIONS.md` für formatierte Kontextbereitstellung.
## Nächste Verbesserungen (Empfehlungen)
- Konsolidierung auf iText7 (Legacy 5.x entfernen).
- Einheitliche Exception-Strategie (momentan Logging + bool Rückgabe).
- Mehr Unit Tests (Persistenz, Controller Interaktionen via Arquillian / Payara Micro).
- Migrationspfad Richtung Jakarta EE 9+ (Namespace Wechsel).
---
Letzte Aktualisierung: 2025-10-20
+54
View File
@@ -0,0 +1,54 @@
# Domain: SecurityArea
## Zweck
Abbildung eines Schutzbereichs einer Maschine mit zugehörigen Schutzeinrichtungen, Gefahrenstellen und Schaltgeräten sowie Fragebögen zur Bewertung.
## Haupt-Entitäten (Ausschnitt)
- `SecurityArea`
- `SecurityDevice` (Liste in Area)
- `DangerPoint`
- `SwitchingDevice`
- `SecurityAreaQuestionnaire` (assoziative Entity zwischen Schutzbereich und `Questionaire`)
- `Questionaire`
## Lebenszyklus
1. Erstellung im UI: Neues `SecurityArea` Objekt mit Fake-ID (negativ).
2. Bearbeitung von Eigenschaften (Name, Typen/Enums: `ProtectionType`, `MountingPosition`, `OverrunMeasurementType`, `ApproachSpeed`).
3. Hinzufügen von Schutzeinrichtungen/Gefahrenstellen/Schaltgeräten (ebenfalls ggf. mit Fake-ID bis persistiert).
4. Speichern: Negative IDs der neuen Objekte werden auf `null` gesetzt → Persist durch `SecurityAreaManager.save` / Sammelspeicher.
5. Nach Persist: Re-Load (`refresh`/`reloadWithQuestionnaires`) vor weiterer Bearbeitung.
## Klonen
`SecurityAreaManager.cloneArea(SecurityArea area)`:
- Lädt persistente Quelle (falls ID > 0) vollständig.
- Erzeugt neue Kopie via Copy-Konstruktor.
- Controller passt Namen an (`Original (Kopie)`), setzt neue `null` IDs für untergeordnete Objekte.
## Fragebogen-Verknüpfung
### Hinzufügen
- Methode: `addQuestionnaireToSecurityArea(area, questionnaire)`.
- Erzeugt `SecurityAreaQuestionnaire` Wrapper.
- Persist Wrapper, merge Area.
- UI aktualisiert Liste und sendet Erfolgsmeldung.
### Entfernen
- `removeQuestionnaireFromSecurityArea(area, securityAreaQuestionnaire)` entfernt Element aus Sammlung & ruft `em.remove`.
### Verfügbare Fragebögen
- `getAvailableQuestionnaires(area)` holt alle `Questionaire` und filtert bereits zugeordnete anhand Name. Verbesserung: Nutzung ID statt Name zur Eindeutigkeit.
## Konsistenz / Referentielle Integrität
Beim Löschen eines Schutzbereichs (`deleteSelected()` im Controller):
1. Entfernen aus Maschine.
2. Auflösen aller Kind-Referenzen (SwitchingDevices, DangerPoints, SecurityDevices) durch Setzen der Area auf `null`.
3. Entfernen der Kindobjekte via entsprechende Manager (`removeAllIn`).
4. Löschen des `SecurityArea` via Named Query (`SecurityArea.DELETE`).
## Potentielle Verbesserungen
- Cascade Settings genauer prüfen (evtl. kann Teil der manuellen Löschlogik automatisiert werden).
- Validierung (Bean Validation) für Pflichtfelder (Name nicht leer, Enums nicht null soweit fachlich notwendig).
- Nutzung DTOs zur Entkopplung UI ↔ JPA (reduziert Lazy Probleme).
---
Aktualisiert: 2025-10-20
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scene Scope="Project" version="2">
<Scope Scope="Faces Configuration Only"/>
<Scope Scope="Project"/>
<Scope Scope="All Faces Configurations"/>
</Scene>
-130
View File
@@ -1,130 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>mss-failsafe</artifactId>
<groupId>plate.software</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>plate.software</groupId>
<artifactId>mss</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mss-1.0-SNAPSHOT</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
<jakartaee>8.0</jakartaee>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.soteria</groupId>
<artifactId>javax.security.enterprise</artifactId>
<version>1.0</version> <!-- Stable version -->
</dependency>
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.11.1</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>10.0.0</version>
</dependency>
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>primeflex</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -1,65 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business;
import java.util.List;
import javax.persistence.EntityManager;
/**
*
* @author Patrick
* @param <T>
*/
public abstract class AbstractManager<T> {
private Class<T> entityClass;
public AbstractManager(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0] + 1);
q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
@@ -1,36 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.user;
import javax.ejb.EJB;
import javax.ejb.Startup;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
/**
*
* @author patri
*/
@Named(value = "DemoManager")
@ApplicationScoped
@Startup
public class DemoManager {
@EJB
PersonManager personManager;
/**
* Creates a new instance of NewJSFManagedBean
*/
public DemoManager() {
runDemos();
}
private void runDemos(){
personManager.demo();
}
}
@@ -1,91 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.user;
import java.time.Instant;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.util.UUID.randomUUID;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import exception.InvalidEmailException;
import model.person.Token;
import model.person.enums.TokenType;
import model.person.Person;
import java.util.Arrays;
import static java.time.Instant.now;
/**
*
* @author Patrick
*/
@Stateless
public class TokenManager {
@PersistenceContext(name = "pu_person")
private EntityManager em;
@Inject
PasswordManager passwordManager;
@Inject
PersonManager customerManager;
public String generate(final String email, final String ipAddress, final String description,
final TokenType tokenType) {
String rawToken = randomUUID().toString();
Instant expiration = now().plus(14, DAYS);
save(rawToken, email, ipAddress, description, tokenType, expiration);
return rawToken;
}
public String generateFileToken(final String email, final String description) {
String rawToken = randomUUID().toString();
Instant expiration = now().plus(3, DAYS);
save(rawToken, email, null, description, TokenType.FILE, expiration);
return rawToken;
}
public void save(final String rawToken, final String email, final String ipAddress,
final String description, final TokenType tokenType, final Instant expiration) {
Person user = this.customerManager.getByEmail(email)
.orElseThrow(InvalidEmailException::new);
Token token = new Token();
token.setTokenHash(Arrays.toString(this.passwordManager.hashToken(rawToken)));
token.setExpiration(expiration);
token.setDescription(description);
token.setTokenType(tokenType);
token.setIpAddress(ipAddress);
user.addToken(token);
this.em.persist(user);
}
public void remove(String token) {
this.em.createNamedQuery(Token.REMOVE_TOKEN)
.setParameter("tokenHash", token).executeUpdate();
}
public void removeExpired() {
this.em.createNamedQuery(Token.REMOVE_EXPIRED_TOKEN)
.setParameter("timestamp", Instant.now())
.executeUpdate();
}
}
@@ -1,53 +0,0 @@
package controller;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
/**
*
* @author Patrick
*/
public abstract class AbstractController implements Serializable{
private static final long serialVersionUID = -5908716187853409719L;
protected void sendInfoMessage(String title, String message){
FacesMessage facesMessage = new FacesMessage(
FacesMessage.SEVERITY_INFO, title, message);
addMessage(facesMessage);
}
protected void sendWarnMessage(String title, String message){
FacesMessage facesMessage = new FacesMessage(
FacesMessage.SEVERITY_WARN, title, message);
addMessage(facesMessage);
}
protected void sendErrorMessage(String title, String message){
FacesMessage facesMessage = new FacesMessage(
FacesMessage.SEVERITY_ERROR, title, message);
addMessage(facesMessage);
}
protected void sendFatalMessage(String title, String message){
FacesMessage facesMessage = new FacesMessage(
FacesMessage.SEVERITY_FATAL, title, message);
addMessage(facesMessage);
}
private void addMessage(FacesMessage message) {
FacesContext.getCurrentInstance().addMessage(null, message);
}
protected void errorMessage() {
String title = "Fehler!";
String info = "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut!";
sendErrorMessage(title, info);
}
}
@@ -1,127 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package controller.person;
import controller.AbstractController;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import model.person.Person;
import model.person.enums.Call;
/**
*
* @author patri
*/
@Named
@RequestScoped
public class PersonEditController extends AbstractController{
@Inject
PersonController personController;
private String email;
private Call call;
private String telefon;
private String password;
private String mobile;
private String fax;
private String firstname;
private String lastname;
private String title;
public PersonEditController() {
}
@PostConstruct
private void loadUserdata(){
Person activePerson = personController.getActiveUser();
email = activePerson.getEmail();
call = activePerson.getCall();
telefon = activePerson.getTelefon();
password = "********";
mobile = activePerson.getMobile();
fax = activePerson.getFax();
firstname = activePerson.getFirstname();
lastname = activePerson.getLastname();
title = activePerson.getTitle();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Call getCall() {
return call;
}
public void setCall(Call call) {
this.call = call;
}
public String getTelefon() {
return telefon;
}
public void setTelefon(String telefon) {
this.telefon = telefon;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getFax() {
return fax;
}
public void setFax(String fax) {
this.fax = fax;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@@ -1,92 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package controller.person;
import business.user.PersonManager;
import business.user.UserPictureManager;
import controller.AbstractController;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import model.files.Mime;
import model.files.UserPicture;
import model.person.Person;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.file.UploadedFile;
/**
*
* @author patri
*/
@Named
@RequestScoped
public class UserPictureController extends AbstractController {
private UserPicture picture;
@Inject
PersonController personController;
@EJB
UserPictureManager upManager;
@EJB
PersonManager personManager;
public void handleUserPictureUpload(FileUploadEvent event) {
UploadedFile file = event.getFile();
if (file != null && file.getContent() != null && file.getContent().length > 0 && file.getFileName() != null) {
if (createSaveUserPicture(file)) {
sendInfoMessage("Erfolg", this.picture.getName() + " wurde hochgeladen!");
} else {
sendErrorMessage("Fehler", "Es ist ein Fehler aufgetreten. Bitte Versuchen Sie es erneut!");
}
}
}
private boolean createSaveUserPicture(UploadedFile file) {
picture = null;
picture = personController.getActiveUser().getUserPicture();
boolean isNew = picture == null;
if (isNew) {
picture = new UserPicture();
}
setData(picture, file);
Person person = personManager.load(personController.getActiveUser());
person.setUserPicture(picture);
picture.setPerson(person);
if (isNew) {
upManager.create(picture);
} else {
upManager.edit(picture);
}
personManager.save(person);
personController.reloadActivePerson();
return true;
}
private void setData(UserPicture picture, UploadedFile file) {
picture.setName(file.getFileName());
picture.setFileData(file.getContent());
picture.setMime(Mime.getByMimeType(file.getContentType()));
}
public long getMaxFileSize() {
return UserPicture.getSizeLimit();
}
public String getFileTypesRE() {
return UserPicture.getAllowedTypesRE();
}
}
@@ -1,77 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package httpauthenticationmechanism;
import javax.enterprise.context.ApplicationScoped;
import javax.security.enterprise.credential.CallerOnlyCredential;
import javax.security.enterprise.credential.Credential;
import javax.security.enterprise.credential.UsernamePasswordCredential;
import javax.security.enterprise.identitystore.CredentialValidationResult;
import static javax.security.enterprise.identitystore.CredentialValidationResult.INVALID_RESULT;
import static javax.security.enterprise.identitystore.CredentialValidationResult.NOT_VALIDATED_RESULT;
import javax.security.enterprise.identitystore.IdentityStore;
import business.user.PersonManager;
import exception.InvalidCredentialException;
import java.util.Set;
import java.util.stream.Collectors;
import javax.ejb.EJB;
import model.person.Person;
/**
*
* @author Patrick
*/
@ApplicationScoped
public class AppIdentityStore implements IdentityStore {
@EJB
PersonManager userManager;
@Override
public int priority() {
return 90;
}
@Override
public CredentialValidationResult validate(Credential credential) {
try {
// check if the credential was UsernamePasswordCredential
if (credential instanceof UsernamePasswordCredential) {
String username = ((UsernamePasswordCredential) credential).getCaller();
String password = ((UsernamePasswordCredential) credential).getPasswordAsString();
return validate(this.userManager.getByEmailAndPassword(username, password));
}
// check if the credential was CallerOnlyCredential
if (credential instanceof CallerOnlyCredential) {
String username = ((CallerOnlyCredential) credential).getCaller();
return validate(
this.userManager.getByEmail(username)
.orElseThrow(InvalidCredentialException::new)
);
}
} catch (InvalidCredentialException e) {
return INVALID_RESULT;
}
return NOT_VALIDATED_RESULT;
}
private CredentialValidationResult validate(Person person) {
Set<String> groups;
groups = person.getUserGroups().stream()
.map(gr -> gr.toString())
.collect(Collectors.toSet());
return new CredentialValidationResult(person.getEmail(), groups);
}
}
@@ -1,85 +0,0 @@
package httpauthenticationmechanism;
import business.user.PersonManager;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.security.enterprise.AuthenticationStatus;
import javax.security.enterprise.authentication.mechanism.http.AutoApplySession;
import javax.security.enterprise.authentication.mechanism.http.CustomFormAuthenticationMechanismDefinition;
import javax.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism;
import javax.security.enterprise.authentication.mechanism.http.HttpMessageContext;
import javax.security.enterprise.authentication.mechanism.http.LoginToContinue;
import javax.security.enterprise.authentication.mechanism.http.RememberMe;
import javax.security.enterprise.credential.Credential;
import javax.security.enterprise.identitystore.IdentityStore;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
*
* @author Patrick
*/
@AutoApplySession // For "Is user already logged-in?"
@RememberMe(
cookieMaxAgeSeconds = 60 * 60 * 24 * 14, // 14 days
cookieSecureOnly = false, // Remove this when login is served over HTTPS.
isRememberMeExpression = "#{self.isRememberMe(httpMessageContext)}"
)
@LoginToContinue(
loginPage = "/index.xhtml",
errorPage = "/error.xhtml",
useForwardToLogin = true
)
@ApplicationScoped
public class ApplicationConfig implements HttpAuthenticationMechanism{
final static Logger LOGGER = LogManager.getLogger(ApplicationConfig.class);
public ApplicationConfig() {
}
@Inject
private IdentityStore identityStore;
@Inject
private ManagedPerson managedPerson;
@EJB
private PersonManager personManager;
@PostConstruct
private void init(){
managedPerson.getLogins();
personManager.demo();
System.out.println("PostConstruct DEMO");
}
@Override
public AuthenticationStatus validateRequest(HttpServletRequest req, HttpServletResponse res, HttpMessageContext context) {
Credential credential = context.getAuthParameters().getCredential();
if (credential != null) {
return context.notifyContainerAboutLogin(this.identityStore.validate(credential));
} else {
return context.doNothing();
}
}
// this was called on @RememberMe annotations
public Boolean isRememberMe(HttpMessageContext httpMessageContext) {
return httpMessageContext.getAuthParameters().isRememberMe();
}
@Override
public void cleanSubject(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) {
HttpAuthenticationMechanism.super.cleanSubject(request, response, httpMessageContext);
}
}
@@ -1,45 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package httpauthenticationmechanism;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;
/**
*
* @author Patrick
*/
@Named(value = "managedPerson")
@ApplicationScoped
public class ManagedPerson {
private Set<String> logins;
/**
* Creates a new instance of ManagedCustomer
*/
public ManagedPerson() {
}
public Set<String> getLogins(){
if (this.logins == null) {
this.logins = new HashSet<>();
}
return this.logins;
}
public void addLogin(String user){
getLogins().add(user);
}
public void removeLogin(String user){
getLogins().remove(user);
}
}
@@ -1,214 +0,0 @@
package model.adresses;
import java.util.Objects;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
import model.AbstractEntity;
/**
*
* @author Patrick
*/
@MappedSuperclass
public class Address extends AbstractEntity{
//Land
@NotNull(message = "Land darf nicht null sein")
private String country;
//Straßenname
@NotNull(message = "Strasse darf nicht null sein")
private String street;
//Hausnummer
@NotNull(message = "Hausnummer darf nicht null sein")
private String number;
//Zusatz
private String extra;
//PLZ
@NotNull(message = "PLZ darf nicht null sein")
private Integer postnumber;
//Bundesland
@NotNull(message = "Bundesland darf nicht null sein")
private String county;
//Ort
@NotNull(message = "Ort darf nicht null sein")
private String place;
private String contact;
private String comment;
public Address() {
}
public Address(String street, String number, String extra, Integer postnumber, String county, String place) {
this.street = street;
this.number = number;
this.extra = extra;
this.postnumber = postnumber;
this.county = county;
this.place = place;
}
public Address(String country, String street, String number, String extra, Integer postnumber, String county, String place) {
this.country = country;
this.street = street;
this.number = number;
this.extra = extra;
this.postnumber = postnumber;
this.county = county;
this.place = place;
}
public Address(String country, String street, String number, String extra, Integer postnumber, String county, String place, String contact, String comment) {
this.country = country;
this.street = street;
this.number = number;
this.extra = extra;
this.postnumber = postnumber;
this.county = county;
this.place = place;
this.contact = contact;
this.comment = comment;
}
public Address(Address toCopyAddress){
this.country = toCopyAddress.getCountry();
this.street = toCopyAddress.getStreet();
this.number = toCopyAddress.getNumber();
this.extra = toCopyAddress.getExtra();
this.postnumber = toCopyAddress.getPostnumber();
this.county = toCopyAddress.getCounty();
this.place = toCopyAddress.getPlace();
this.contact = toCopyAddress.getContact();
this.comment = toCopyAddress.getComment();
}
@Override
public int hashCode() {
int hash = 7;
hash = 83 * hash + Objects.hashCode(this.country);
hash = 83 * hash + Objects.hashCode(this.street);
hash = 83 * hash + Objects.hashCode(this.number);
hash = 83 * hash + Objects.hashCode(this.extra);
hash = 83 * hash + Objects.hashCode(this.postnumber);
hash = 83 * hash + Objects.hashCode(this.county);
hash = 83 * hash + Objects.hashCode(this.place);
hash = 83 * hash + Objects.hashCode(this.contact);
hash = 83 * hash + Objects.hashCode(this.comment);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Address other = (Address) obj;
if (!Objects.equals(this.country, other.country)) {
return false;
}
if (!Objects.equals(this.street, other.street)) {
return false;
}
if (!Objects.equals(this.number, other.number)) {
return false;
}
if (!Objects.equals(this.extra, other.extra)) {
return false;
}
if (!Objects.equals(this.county, other.county)) {
return false;
}
if (!Objects.equals(this.place, other.place)) {
return false;
}
if (!Objects.equals(this.comment, other.comment)) {
return false;
}
return Objects.equals(this.postnumber, other.postnumber);
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
public Integer getPostnumber() {
return postnumber;
}
public void setPostnumber(Integer postnumber) {
this.postnumber = postnumber;
}
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
@@ -1,73 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.company;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import model.AbstractEntity;
import model.adresses.LocationAddress;
import model.customer.Customer;
import model.machine.Machine;
/**
*
* @author patri
*/
@Entity
public class Location extends AbstractEntity{
@ManyToOne
private Company company;
@OneToOne
private LocationAddress address;
@OneToMany(mappedBy = "location")
private Set<Machine> machines;
@ManyToMany
private Set<Customer> contacts;
public Location() {
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public LocationAddress getAddress() {
return address;
}
public void setAddress(LocationAddress address) {
this.address = address;
}
public Set<Machine> getMachines() {
return machines;
}
public void setMachines(Set<Machine> machines) {
this.machines = machines;
}
public Set<Customer> getContacts() {
return contacts;
}
public void setContacts(Set<Customer> contacts) {
this.contacts = contacts;
}
}
@@ -1,63 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.customer;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import model.person.Person;
import model.company.Company;
import model.company.Location;
/**
*
* @author patri
*/
@Entity
public class Customer extends Person{
@ManyToOne
private Company company;
@ManyToMany
private Set<Location> locations;
@Column(nullable = true, length = 210)
private String note;
public Customer() {
}
public Customer(Company company) {
this.company = company;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public Set<Location> getLocations() {
return locations;
}
public void setLocations(Set<Location> locations) {
this.locations = locations;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
@@ -1,33 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.machine;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import model.AbstractEntity;
import model.company.Location;
/**
*
* @author patri
*/
@Entity
public class Machine extends AbstractEntity {
@ManyToOne
private Location location;
public Machine() {
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
@@ -1,131 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import java.time.LocalDateTime;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import model.AbstractEntity;
import model.person.Person;
/**
*
* @author Patrick
*/
@Entity
public class Comment extends AbstractEntity implements Comparable<Comment> {
@Column(columnDefinition = "longblob")
private String message;
@ManyToOne
private Person writer;
private boolean edited;
@ManyToOne
private Ticket ticket;
public Comment() {
}
public Comment(Person writer, String message) {
this.writer = writer;
this.edited = false;
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
edited = true;
}
public LocalDateTime getLastEditedDate() {
return getChangedDate();
}
public boolean isEdited() {
return edited;
}
public void setEdited(boolean edited) {
this.edited = edited;
setChangedDate(LocalDateTime.now());
}
public Ticket getTicket() {
return ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
setChangedDate(LocalDateTime.now());
}
public Person getWriter() {
return writer;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.message);
hash = 79 * hash + Objects.hashCode(this.writer);
hash = 79 * hash + Objects.hashCode(getCreationDate());
hash = 79 * hash + Objects.hashCode(getChangedDate());
hash = 79 * hash + (this.edited ? 1 : 0);
hash = 79 * hash + Objects.hashCode(this.ticket);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Comment other = (Comment) obj;
if (this.edited != other.edited) {
return false;
}
if (!Objects.equals(this.message, other.message)) {
return false;
}
if (!Objects.equals(this.writer, other.writer)) {
return false;
}
if (!Objects.equals(getCreationDate(), other.getCreationDate())) {
return false;
}
if (!Objects.equals(this.ticket, other.ticket)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Comment{" + "writer=" + writer.getEmail() + ", creationDate=" + getCreationDate() + ", id=" + getId() + ", message="+ message + '}';
}
@Override
public int compareTo(Comment c) {
return c.getCreationDate().compareTo(this.getCreationDate());
}
}
@@ -1,32 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
/**
*
* @author patri
*/
public enum FilenameGeneration {
INSPEKTIONNR,
MASCHINEDESCRIPTION,
LOCATION;
@Override
public String toString() {
switch(this){
case INSPEKTIONNR:
return "inspektionnr";
case MASCHINEDESCRIPTION:
return "maschinedescription";
case LOCATION:
return "location";
}
return "nothing";
}
}
@@ -1,46 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import model.AbstractEntity;
import javax.persistence.OneToOne;
import model.machine.Machine;
/**
*
* @author patri
*/
@Entity
public class LocationMachine extends AbstractEntity{
@OneToOne
private Machine machine;
@ManyToOne
private TicketLocation ticketLocation;
public LocationMachine() {
}
public Machine getMachine() {
return machine;
}
public void setMachine(Machine machine) {
this.machine = machine;
}
public TicketLocation getTicketLocation() {
return ticketLocation;
}
public void setTicketLocation(TicketLocation ticketLocation) {
this.ticketLocation = ticketLocation;
}
}
@@ -1,189 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import model.AbstractEntity;
import model.adresses.CompanyBillingAddress;
import model.company.Company;
import model.files.Invoice;
import model.files.Report;
import model.person.Person;
import model.person.Token;
/**
*
* @author patri
*/
@Entity
public class Ticket extends AbstractEntity{
@ManyToOne(optional = false)
private Company company;
@OneToOne
private CompanyBillingAddress billingAddress;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private Status status;
@OneToOne(optional = false)
private Person creator;
@OneToOne(optional = true)
private Person owner;
private LocalDateTime startDate;
private LocalDateTime endDate;
@OneToMany(mappedBy = "ticket", cascade = CascadeType.ALL)
private List<Comment> comments;
private boolean payed;
@OneToMany(mappedBy = "ticket", orphanRemoval = true, cascade = CascadeType.ALL)
private List<Token> tokens;
@OneToMany(mappedBy = "ticket", cascade = {CascadeType.PERSIST, CascadeType.PERSIST})
private List<Report> reports;
@OneToMany(mappedBy = "ticket", cascade = {CascadeType.PERSIST, CascadeType.PERSIST})
private List<Invoice> invoices;
@OneToMany(mappedBy = "ticket", cascade = {CascadeType.PERSIST, CascadeType.PERSIST})
private List<TicketLocation> locations;
@Column(nullable = false, length = 200)
private String filenameGeneration;
public Ticket() {
}
public CompanyBillingAddress getBillingAddress() {
return billingAddress;
}
public void setBillingAddress(CompanyBillingAddress billingAddress) {
this.billingAddress = billingAddress;
}
public LocalDateTime getStartDate() {
return startDate;
}
public void setStartDate(LocalDateTime startDate) {
this.startDate = startDate;
}
public LocalDateTime getEndDate() {
return endDate;
}
public void setEndDate(LocalDateTime endDate) {
this.endDate = endDate;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public List<TicketLocation> getLocations() {
return locations;
}
public void setLocations(List<TicketLocation> locations) {
this.locations = locations;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Person getCreator() {
return creator;
}
public void setCreator(Person creator) {
this.creator = creator;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public boolean isPayed() {
return payed;
}
public void setPayed(boolean payed) {
this.payed = payed;
}
public List<Token> getTokens() {
return tokens;
}
public void setTokens(List<Token> tokens) {
this.tokens = tokens;
}
public List<Report> getReports() {
return reports;
}
public void setReports(List<Report> reports) {
this.reports = reports;
}
public List<Invoice> getInvoices() {
return invoices;
}
public void setInvoices(List<Invoice> invoices) {
this.invoices = invoices;
}
public String getFilenameGeneration() {
return filenameGeneration;
}
public void setFilenameGeneration(String filenameGeneration) {
this.filenameGeneration = filenameGeneration;
}
}
@@ -1,58 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import model.AbstractEntity;
import model.company.Location;
import java.util.List;
import javax.persistence.OneToMany;
/**
*
* @author patri
*/
@Entity
public class TicketLocation extends AbstractEntity{
@ManyToOne
private Ticket ticket;
@OneToOne
private Location location;
@OneToMany(mappedBy = "ticketLocation")
private List<LocationMachine> machines;
public TicketLocation() {
}
public Ticket getTicket() {
return ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public List<LocationMachine> getMachines() {
return machines;
}
public void setMachines(List<LocationMachine> machines) {
this.machines = machines;
}
}
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="all">
</beans>
@@ -1,6 +0,0 @@
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_10_0.xsd"
version="10.0">
<security-domain>mss-failsafe</security-domain>
</jboss-web>
@@ -1,14 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}</title>
</h:head>
<h:body>
<p>Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}</p>
<p:spinner />
</h:body>
</html>
@@ -1,35 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<h:head>
<title>Login Testpage</title>
</h:head>
<h:body>
<h:form id="login">
<p:panel header="Login" style="width: 450px; margin: auto; margin-top: 100px;">
<p:messages id="messages" showDetail="true" closable="true">
<p:autoUpdate />
</p:messages>
<p:graphicImage url="/resources/images/logo.jpg" alt="MSS Machine Safety Services" style="width: 100%;"/>
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="username" value="Email" />
<p:inputText id="username" value="#{personController.username}" required="true" label="username" />
<p:outputLabel for="password" value="Password:" />
<p:password id="password" value="#{personController.password}" required="true" label="password" />
<p:outputLabel for="rememberMe" value="Remember Me:" />
<p:selectBooleanCheckbox id="rememberMe" value="#{personController.rememberMe}" />
<f:facet name="footer">
<p:commandButton value="Login" action="#{personController.submit()}" ajax="false"/>
</f:facet>
</h:panelGrid>
</p:panel>
</h:form>
</h:body>
</html>
@@ -1,83 +0,0 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f = "http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<f:facet name="last">
<h:outputStylesheet library="css" name="default.css"/>
<h:outputStylesheet library="css" name="icons.css"/>
<h:outputStylesheet library="webjars" name="primeflex/2.0.0/primeflex.min.css" />
</f:facet>
<title>
<ui:insert name="title">
Please add a Title!
</ui:insert>
</title>
<ui:insert name="head"/>
</h:head>
<h:body>
<h:form id="main">
<div class="p-grid">
<div class="p-col-12 p-md-3 p-lg-2 p-xl-2">
<div class="p-col-12" style="min-height: 90px;">
<p:commandLink action="welcome">
<p:graphicImage url="../resources/images/logo.jpg" alt="MSS Machine Safety Services" style="width: 100%;"/>
</p:commandLink>
</div>
<div class="p-col-12">
<p:menu style="width: 100%;">
<p:submenu label="Home">
<p:menuitem value="Home" outcome="welcome" icon="pi pi-home"/>
<p:menuitem value="Suche" outcome="welcome" icon="pi pi-search"/>
</p:submenu>
<p:submenu label="Ticket">
<p:menuitem value="Erstellen" outcome="welcome" icon="pi pi-plus"/>
<p:menuitem value="Suchen" outcome="welcome" icon="pi pi-search"/>
</p:submenu>
<p:submenu label="Stammdaten">
<p:menuitem value="Firmen" outcome="companies" icon="icon company"/>
<p:menuitem value="Standorte" outcome="locations" icon="icon location"/>
<p:menuitem value="Maschienen" outcome="machines" icon="icon machine"/>
<p:menuitem value="Schutzeinr." outcome="protection" icon="icon security"/>
</p:submenu>
</p:menu>
</div>
</div>
<div class="p-col-12 p-md-9 p-lg-10 p-xl-10">
<div class="card p-col-12" style="min-height: 90px; text-align: right;">
<p:menu overlay="true" trigger="avatar" my="left top" at="bottom left">
<p:menuitem value="Profil" outcome="profile"/>
<p:menuitem value="Einstellungen" />
<p:menuitem value="Ausloggen" action="#{personController.logout()}" />
</p:menu>
<p:avatar dynamicColor="true" id="avatar" icon="pi pi-user" styleClass="p-mr-2 avatar" size="large" shape="circle" gravatar="#{personController.activeUser.email}">
<p:graphicImage value="#{personController.activeUser.userPicture.fileData}" rendered="#{personController.hasPicture()}"/>
</p:avatar>
</div>
<div class="p-col-12" style="width: 100%">
<div class="card p-col-12">
<p:growl showDetail="true">
<p:autoUpdate/>
</p:growl>
</div>
<div class="card p-col-12">
<ui:insert name="content">Content</ui:insert>
</div>
</div>
</div>
<div class="p-col-12 p-lg-12 p-xl-12">
<ui:insert name="bottom">Bottom</ui:insert>
</div>
</div>
</h:form>
</h:body>
</html>
@@ -1,19 +0,0 @@
<ui:composition template="/resources/layout/user/template.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:define name="title">
Firmen
</ui:define>
<ui:define name="content">
Willkommen zuhause
</ui:define>
<ui:define name="bottom">
</ui:define>
</ui:composition>
@@ -1,110 +0,0 @@
<ui:composition template="/resources/layout/user/template.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:define name="title">
Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}
</ui:define>
<ui:define name="content">
<div class="p-grid">
<div class="card p-col-5 p-md-6 p-xl-6">
<p:fileUpload mode="advanced"
multiple="false"
sizeLimit="#{userPictureController.maxFileSize}" allowTypes="#{userPictureController.fileTypesRE}"
invalidSizeMessage="Maximum file size allowed is 2 MB"
invalidFileMessage="only gif | jpg | jpeg | png is allowed"
update="main"
listener="#{userPictureController.handleUserPictureUpload}"/>
</div>
<div class="card p-col-7 p-md-6 p-xl-6" style="text-align: right;">
<p:graphicImage style="max-width: 500px; max-height: 300px; margin-right: 20%;" id="image" value="#{personController.activeUser.userPicture.fileData}" rendered="#{personController.hasPicture()}"/>
</div>
<div class="card p-col-12 p-md-6 p-xl-6">
<div class="ui-fluid p-formgrid p-grid">
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="email" value="Email" />
<p:inputText readonly="true" id="email" value="#{personEditController.email}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="password" value="Password" />
<p:inputText readonly="true" id="password" value="#{personEditController.password}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="telefon" value="Telefon" />
<p:inputText readonly="true" id="telefon" value="#{personEditController.telefon}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="mobile" value="Handy" />
<p:inputText readonly="true" id="mobile" value="#{personEditController.mobile}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
</div>
</div>
<div class="card p-col-12 p-md-6 p-xl-6">
<div class="ui-fluid p-formgrid p-grid">
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="title" value="Titel" />
<p:inputText readonly="true" id="title" value="#{personEditController.title}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="call" value="Anrede" />
<p:inputText readonly="true" id="call" value="#{personEditController.call.toString()}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="firstname" value="Vorname" />
<p:inputText readonly="true" id="firstname" value="#{personEditController.firstname}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
<div class="p-field p-col-8 p-md-8">
<p:outputLabel for="lastname" value="Nachname" />
<p:inputText readonly="true" id="lastname" value="#{personEditController.lastname}" />
</div>
<div class="p-field p-col-4 p-md-4" style="float: right;">
<br />
<p:commandButton value="Ändern"/>
</div>
</div>
</div>
</div>
</ui:define>
<ui:define name="bottom">
</ui:define>
</ui:composition>
@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>plate.software</groupId>
<artifactId>mss-failsafe</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>mssfailsafe.datalayer</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
<jakartaee>8.0</jakartaee>
</properties>
<dependencies>
<dependency>
<groupId>plate.software</groupId>
<artifactId>userdata</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>plate.software</groupId>
<artifactId>userManagement</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>classes</classifier>
</dependency>
</dependencies>
</project>
@@ -1,32 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.adresses;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import model.company.Location;
/**
*
* @author patri
*/
@Entity
public class LocationAddress extends Address {
@OneToOne
private Location location;
public LocationAddress() {
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
@@ -1,151 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.company;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.OneToMany;
import model.AbstractEntity;
import model.adresses.CompanyBillingAddress;
import model.customer.Customer;
/**
*
* @author patri
*/
@Entity
public class Company extends AbstractEntity {
public static final String FIND_BY_NAME = "Company.findByName";
public static final String FIND_BY_STEUERID = "Company.findBySteuerID";
public static final String FIND_BY_UMSATZSTEUERID = "Company.findByUmsatzsteuerID";
public static final String FIND_BY_CUSTOMER = "Company.findByCustomer";
public static final String FIND_BY_ADDRESS = "Company.findByAddress";
public static final String FIND_BY_DELIVERYADDRESS = "Company.findByLocation";
@Column(unique = true, nullable = false)
private String name;
@Column(unique = true, nullable = true)
private String steuerNr;
@Column(unique = true, nullable = true)
private String umsatzSteuerID;
@Column(unique = true, nullable = true)
private String kundenNr;
@Column(unique = false, nullable = true)
private String headerInspection;
@Column(unique = false, nullable = true)
private String headerService;
@Column(unique = false, nullable = false)
@Enumerated(EnumType.ORDINAL)
private Status status;
@OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
private Set<CompanyBillingAddress> addresses;
@OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
private Set<Location> locations;
@OneToMany(mappedBy = "company", cascade = {
CascadeType.MERGE,
CascadeType.REFRESH
})
private Set<Customer> customers;
public Company() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSteuerNr() {
return steuerNr;
}
public void setSteuerNr(String steuerNr) {
this.steuerNr = steuerNr;
}
public String getUmsatzSteuerID() {
return umsatzSteuerID;
}
public void setUmsatzSteuerID(String umsatzSteuerID) {
this.umsatzSteuerID = umsatzSteuerID;
}
public String getKundenNr() {
return kundenNr;
}
public void setKundenNr(String kundenNr) {
this.kundenNr = kundenNr;
}
public String getHeaderInspection() {
return headerInspection;
}
public void setHeaderInspection(String headerInspection) {
this.headerInspection = headerInspection;
}
public String getHeaderService() {
return headerService;
}
public void setHeaderService(String headerService) {
this.headerService = headerService;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Set<CompanyBillingAddress> getAddresses() {
return addresses;
}
public void setAddresses(Set<CompanyBillingAddress> addresses) {
this.addresses = addresses;
}
public Set<Location> getLocations() {
return locations;
}
public void setLocations(Set<Location> locations) {
this.locations = locations;
}
public Set<Customer> getCustomers() {
return customers;
}
public void setCustomers(Set<Customer> customers) {
this.customers = customers;
}
}
@@ -1,73 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.company;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import model.AbstractEntity;
import model.adresses.LocationAddress;
import model.customer.Customer;
import model.machine.Machine;
/**
*
* @author patri
*/
@Entity
public class Location extends AbstractEntity{
@ManyToOne
private Company company;
@OneToOne
private LocationAddress address;
@OneToMany(mappedBy = "location")
private Set<Machine> machines;
@ManyToMany
private Set<Customer> contacts;
public Location() {
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public LocationAddress getAddress() {
return address;
}
public void setAddress(LocationAddress address) {
this.address = address;
}
public Set<Machine> getMachines() {
return machines;
}
public void setMachines(Set<Machine> machines) {
this.machines = machines;
}
public Set<Customer> getContacts() {
return contacts;
}
public void setContacts(Set<Customer> contacts) {
this.contacts = contacts;
}
}
@@ -1,59 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.company;
import java.util.Locale;
/**
*
* @author patri
*/
public enum Status {
ACTIVE,
INACTIVE;
private Status() {
}
@Override
public String toString() {
switch(this){
case ACTIVE:
return "aktiv";
case INACTIVE:
return "inaktiv";
default:
return "";
}
}
public String toLanguageString(Locale locale){
if (locale == null ||locale.equals(Locale.GERMAN) || locale.equals(Locale.GERMANY)) {
return getGerman();
}
if (locale.equals(Locale.ENGLISH)) {
getEnglish();
}
return "";
}
private String getGerman() {
return toString();
}
private String getEnglish(){
switch(this){
case ACTIVE:
return "active";
case INACTIVE:
return "inactive";
default:
return "";
}
}
}
@@ -1,63 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.customer;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import model.person.Person;
import model.company.Company;
import model.company.Location;
/**
*
* @author patri
*/
@Entity
public class Customer extends Person{
@ManyToOne
private Company company;
@ManyToMany
private Set<Location> locations;
@Column(nullable = true, length = 210)
private String note;
public Customer() {
}
public Customer(Company company) {
this.company = company;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public Set<Location> getLocations() {
return locations;
}
public void setLocations(Set<Location> locations) {
this.locations = locations;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
@@ -1,59 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.files;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Lob;
import model.AbstractEntity;
/**
*
* @author patri
*/
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class FileDB extends AbstractEntity{
@Column(nullable = false, length = 100)
private String name;
@Enumerated(EnumType.STRING)
private Mime mime;
@Lob
private byte[] fileData;
public FileDB() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte[] getFileData() {
return fileData;
}
public void setFileData(byte[] fileData) {
this.fileData = fileData;
}
public Mime getMime() {
return mime;
}
public void setMime(Mime mime) {
this.mime = mime;
}
}
@@ -1,35 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.files;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import model.ticket.Ticket;
/**
*
* @author patri
*/
@Entity
public class Invoice extends FileDB {
@OneToMany
private Ticket ticket;
public Invoice() {
}
public Invoice(Ticket ticket) {
this.ticket = ticket;
}
public Ticket getTicket() {
return ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
}
@@ -1,113 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.files;
/**
*
* @author patri
*/
public enum Mime {
AAC(".aac", "AAC audio", "audio/aac"),
ABW(".abw", "AbiWord document", "application/x-abiword"),
ARC(".arc", "Archive document (multiple files embedded)", "application/x-freearc"),
AVI(".avi", "AVI: Audio Video Interleave", "video/x-msvideo"),
AZW(".azw", "Amazon Kindle eBook format", "application/vnd.amazon.ebook"),
BIN(".bin", "Any kind of binary data", "application/octet-stream"),
BMP(".bmp", "Windows OS/2 Bitmap Graphics", "image/bmp"),
BZ(".bz", "BZip archive", "application/x-bzip"),
BZ2(".bz2", "BZip2 archive", "application/x-bzip2"),
CDA(".cda", "CD audio", "application/x-cdf"),
CSH(".csh", "C-Shell script", "application/x-csh"),
CSS(".css", "Cascading Style Sheets (CSS)", "text/css"),
CSV(".csv", "Comma-separated values (CSV", "text/csv"),
DOC(".doc", "Microsoft Word", "application/msword"),
DOCX(".docx", "Microsoft Word (OpenXML)", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
EOT(".eot", "MS Embedded OpenType fonts", "application/vnd.ms-fontobject"),
EPUB(".epub", "Electronic publication (EPUB)", "application/epub+zip"),
GZ(".gz", "GZip Compressed Archive", "application/gzip"),
GIF(".gif", "Graphics Interchange Format (GIF)", "image/gif"),
HTM(".htm", "HyperText Markup Language (HTML)", "text/html"),
HTML(".html", "HyperText Markup Language (HTML)", "text/html"),
ICO(".ico", "Icon format", "image/vnd.microsoft.icon"),
ICS(".ics", "iCalendar format", "text/calendar"),
JAR(".jar", "Java Archive (JAR)", "application/java-archive"),
JPG(".jpg", "JPEG images", "image/jpeg"),
JPEG(".jpeg", "JPEG images", "image/jpeg"),
JS(".js", "JavaScript", "text/javascript"),
JSON(".json", "JSON format", "application/json"),
JSONLD(".jsonld", "JSON-LD format", "application/ld+json"),
MID(".mid", "Musical Instrument Digital Interface (MIDI)", "audio/midi"),
MIDI(".midi", "Musical Instrument Digital Interface (MIDI)", "audio/midi"),
MJS(".mjs", "JavaScript module", "text/javascript"),
MP3(".mp3", "MP3 audio", "audio/mpeg"),
MP4(".mp4", "MP4 video", "video/mp4"),
MPEG(".mpeg", "MPEG Video", "video/mpeg"),
MPKG(".mpkg", "Apple Installer Package", "application/vnd.apple.installer+xml"),
ODP(".odp", "OpenDocument presentation document", "application/vnd.oasis.opendocument.presentation"),
ODS(".ods", "OpenDocument spreadsheet document", "application/vnd.oasis.opendocument.spreadsheet"),
ODT(".odt", "OpenDocument text document", "application/vnd.oasis.opendocument.text"),
OGA(".oga", "OGG audio", "audio/ogg"),
OGV(".ogv", "OGG video", "video/ogg"),
OGX(".ogx", "OGG", "application/ogg"),
OPUUS(".opus", "Opus audio", "audio/opus"),
OTF(".otf", "OpenType font", "font/otf"),
PNG(".png", "Portable Network Graphics", "image/png"),
PDF(".pdf", "Adobe Portable Document Format (PDF)", "application/pdf"),
PHP(".php", "Hypertext Preprocessor (Personal Home Page)", "application/x-httpd-php"),
PPT(".ppt", "Microsoft PowerPoint", "application/vnd.ms-powerpoint"),
PPTX(".pptx", "Microsoft PowerPoint (OpenXML)", "application/vnd.openxmlformats-officedocument.presentationml.presentation"),
RAR(".rar", "RAR archive", "application/vnd.rar"),
RTF(".rtf", "Rich Text Format (RTF)", "application/rtf"),
SH(".sh", "Bourne shell script", "application/x-sh"),
SVG(".svg", "Scalable Vector Graphics (SVG)", "image/svg+xml"),
SWF(".swf", "Small web format (SWF) or Adobe Flash document", "application/x-shockwave-flash"),
TAR(".tar", "Tape Archive (TAR)", "application/x-tar"),
TIF(".tif", "Tagged Image File Format (TIFF)", "image/tiff"),
TIFF(".tiff", "Tagged Image File Format (TIFF)", "image/tiff"),
TS(".ts", "MPEG transport stream", "video/mp2t"),
TTF(".ttf", "TrueType Font", "font/ttf"),
TXT(".txt", "Text, (generally ASCII or ISO 8859-n)", "text/plain"),
VSD(".vsd", "Microsoft Visio", "application/vnd.visio"),
WAV(".wav", "Waveform Audio Format", "audio/wav"),
WEBA(".weba", "WEBM audio", "audio/webm"),
WEBM(".webm", "WEBM video", "video/webm"),
WEBP(".webp", "WEBP image", "image/webp"),
WOFF(".woff", "Web Open Font Format (WOFF)", "font/woff"),
WOFF2(".woff2", "Web Open Font Format (WOFF)", "font/woff2"),
XHTML(".xhtml", "XHTML", "application/xhtml+xml"),
XLS(".xls", "Microsoft Excel", "application/vnd.ms-excel"),
XLSX(".xlsx", "Microsoft Excel (OpenXML)", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
XML(".xml", "XML", "application/xml"),
XUL(".xul", "XUL", "application/vnd.mozilla.xul+xml"),
ZIP(".zip", "ZIP archive", "application/zip"),
GP3V(".3gp", "3GPP audio/video container", "video/3gpp"),
GP3A(".3gp", "3GPP audio/video container", "audio/3gpp"),
G23V(".3g2", "3GPP2 audio/video container", "video/3gpp2"),
G23A(".3g2", "3GPP2 audio/video container", "audio/3gpp2"),
Z7(".7z", "7-zip archive", "application/x-7z-compressed");
private final String extension;
private final String kindOfDocument;
private final String mimeType;
private Mime(String extension, String kindOfDocument, String mimeType) {
this.extension = extension;
this.kindOfDocument = kindOfDocument;
this.mimeType = mimeType;
}
public String getExtension() {
return extension;
}
public String getKindOfDocument() {
return kindOfDocument;
}
public String getMimeType() {
return mimeType;
}
}
@@ -1,32 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.files;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import model.ticket.Ticket;
/**
*
* @author patri
*/
@Entity
public class Report extends FileDB{
@OneToMany
private Ticket ticket;
public Report() {
}
public Ticket getTicket() {
return ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
}
@@ -1,33 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.machine;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import model.AbstractEntity;
import model.company.Location;
/**
*
* @author patri
*/
@Entity
public class Machine extends AbstractEntity {
@ManyToOne
private Location location;
public Machine() {
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
@@ -1,32 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
/**
*
* @author patri
*/
public enum FilenameGeneration {
INSPEKTIONNR,
MASCHINEDESCRIPTION,
LOCATION;
@Override
public String toString() {
switch(this){
case INSPEKTIONNR:
return "inspektionnr";
case MASCHINEDESCRIPTION:
return "maschinedescription";
case LOCATION:
return "location";
}
return "nothing";
}
}
@@ -1,192 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import model.AbstractEntity;
import model.adresses.CompanyBillingAddress;
import model.company.Company;
import model.company.Location;
import model.files.Invoice;
import model.files.Report;
import model.person.Person;
import model.person.Token;
/**
*
* @author patri
*/
@Entity
public class Ticket extends AbstractEntity{
@Column(nullable = false)
@OneToOne
private Company company;
@OneToOne
private CompanyBillingAddress billingAddress;
@OneToMany
private List<Location> locations;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private Status status;
@Column(nullable = false)
@OneToOne
private Person creator;
@Column(nullable = true)
@OneToOne
private Person owner;
private LocalDateTime startDate;
private LocalDateTime endDate;
@OneToMany(mappedBy = "ticket", cascade = CascadeType.ALL)
private List<Comment> comments;
private boolean payed;
@OneToMany(mappedBy = "ticket", orphanRemoval = true, cascade = CascadeType.ALL)
private List<Token> tokens;
@OneToMany(mappedBy = "ticket", cascade = {CascadeType.PERSIST, CascadeType.PERSIST})
private List<Report> reports;
@OneToMany(mappedBy = "ticket", cascade = {CascadeType.PERSIST, CascadeType.PERSIST})
private List<Invoice> invoices;
@Column(nullable = false, length = 200)
private String filenameGeneration;
public Ticket() {
}
public CompanyBillingAddress getBillingAddress() {
return billingAddress;
}
public void setBillingAddress(CompanyBillingAddress billingAddress) {
this.billingAddress = billingAddress;
}
public LocalDateTime getStartDate() {
return startDate;
}
public void setStartDate(LocalDateTime startDate) {
this.startDate = startDate;
}
public LocalDateTime getEndDate() {
return endDate;
}
public void setEndDate(LocalDateTime endDate) {
this.endDate = endDate;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public List<Location> getLocations() {
return locations;
}
public void setLocations(List<Location> locations) {
this.locations = locations;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Person getCreator() {
return creator;
}
public void setCreator(Person creator) {
this.creator = creator;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public boolean isPayed() {
return payed;
}
public void setPayed(boolean payed) {
this.payed = payed;
}
public List<Token> getTokens() {
return tokens;
}
public void setTokens(List<Token> tokens) {
this.tokens = tokens;
}
public List<Report> getReports() {
return reports;
}
public void setReports(List<Report> reports) {
this.reports = reports;
}
public List<Invoice> getInvoices() {
return invoices;
}
public void setInvoices(List<Invoice> invoices) {
this.invoices = invoices;
}
public String getFilenameGeneration() {
return filenameGeneration;
}
public void setFilenameGeneration(String filenameGeneration) {
this.filenameGeneration = filenameGeneration;
}
}
@@ -1,35 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import model.AbstractEntity;
import model.company.Location;
import java.util.List;
/**
*
* @author patri
*/
@Entity
public class TicketLocation extends AbstractEntity{
@ManyToOne
private Ticket ticket;
@OneToOne
private Location location;
private List<TicketMachine> machines;
public TicketLocation() {
}
}
@@ -1,30 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package model.ticket;
import javax.persistence.Entity;
import model.AbstractEntity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import model.machine.Machine;
/**
*
* @author patri
*/
@Entity
public class TicketMachine extends AbstractEntity{
@ManyToOne
private Ticket ticket;
@OneToOne
private Machine machine;
public TicketMachine() {
}
}
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="pu_datalayer" transaction-type="JTA">
<jta-data-source>java:/mss-failsave</jta-data-source>
<class>model.company.Location</class>
<class>model.adresses.LocationAdress</class>
<class>model.machine.Machine</class>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="pu_datalayer" transaction-type="JTA">
<jta-data-source>java:/mss-failsave</jta-data-source>
<class>model.company.Location</class>
<class>model.adresses.LocationAdress</class>
<class>model.machine.Machine</class>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>1.8-web</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
<org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>ide</org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>
</properties>
</project-shared-configuration>
@@ -1,132 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>mss-failsafe</artifactId>
<groupId>plate.software</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>plate.software</groupId>
<artifactId>mssfailsafeWeblayer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mssfailsafeWeblayer-1.0-SNAPSHOT</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
<jakartaee>8.0</jakartaee>
</properties>
<dependencies>
<dependency>
<groupId>plate.software</groupId>
<artifactId>userdata</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.soteria</groupId>
<artifactId>javax.security.enterprise</artifactId>
<version>1.0</version> <!-- Stable version -->
</dependency>
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.11.1</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>10.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -1,13 +0,0 @@
package plate.software.mssfailsafeweblayer;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
* Configures JAX-RS for the application.
* @author Juneau
*/
@ApplicationPath("resources")
public class JAXRSConfiguration extends Application {
}
@@ -1,20 +0,0 @@
package plate.software.mssfailsafeweblayer.resources;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
/**
*
* @author
*/
@Path("javaee8")
public class JavaEE8Resource {
@GET
public Response ping(){
return Response
.ok("ping")
.build();
}
}
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<!-- Define Persistence Unit -->
<persistence-unit name="my_persistence_unit">
</persistence-unit>
</persistence>
@@ -1,6 +0,0 @@
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_10_0.xsd"
version="10.0">
<security-domain>mss-failsafe</security-domain>
</jboss-web>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web version="10.0" xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_10_0.xsd">
<context-root>/mssfailsafeWeblayer-1.0-SNAPSHOT</context-root>
<security-domain>jaspitest</security-domain>
</jboss-web>
@@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
<welcome-file-list>
<welcome-file>/index.xhtml</welcome-file>
</welcome-file-list>
<error-page>
<!-- Missing login -->
<error-code>401</error-code>
<location>/error.xhtml</location>
</error-page>
<error-page>
<!-- Forbidden directory listing -->
<error-code>403</error-code>
<location>/error.xhtml</location>
</error-page>
<security-constraint>
<web-resource-collection>
<web-resource-name>authorise</web-resource-name>
<url-pattern>/user/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>TRACE</http-method>
<http-method>HEAD</http-method>
<http-method>DELETE</http-method>
<http-method>CONNECT</http-method>
<http-method>OPTIONS</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
<role-name>USER</role-name>
</auth-constraint>
<!--
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>-->
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>authorise</web-resource-name>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>TRACE</http-method>
<http-method>HEAD</http-method>
<http-method>DELETE</http-method>
<http-method>CONNECT</http-method>
<http-method>OPTIONS</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
<!--<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>-->
</security-constraint>
<security-role>
<description>Normal User which got invited</description>
<role-name>USER</role-name>
</security-role>
<security-role>
<description>Admin user who can change entries, invite new domains and more..</description>
<role-name>ADMIN</role-name>
</security-role>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
<cookie-config>
<http-only>true</http-only>
<!-- Prevent client side scripting from accessing/manipulating session cookie. -->
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
<!-- This disables URL rewriting. -->
</session-config>
</web-app>
@@ -1,14 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}</title>
</h:head>
<h:body>
<p>Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}</p>
<p:spinner />
</h:body>
</html>
@@ -1,13 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Error Testpage</title>
</h:head>
<h:body>
<p>Error!</p>
</h:body>
</html>
@@ -1,33 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Login Testpage</title>
</h:head>
<h:body>
<h:form id="login">
<p:panel header="Login MSS-Failsafe " style="width: 450px; margin: auto; margin-top: 100px;">
<p:messages id="messages" showDetail="true" closable="true">
<p:autoUpdate />
</p:messages>
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="username" value="Email" />
<p:inputText id="username" value="#{personController.username}" required="true" label="username" />
<p:outputLabel for="password" value="Password:" />
<p:password id="password" value="#{personController.password}" required="true" label="password" />
<p:outputLabel for="rememberMe" value="Remember Me:" />
<p:selectBooleanCheckbox id="rememberMe" value="#{personController.rememberMe}" />
<f:facet name="footer">
<p:commandButton value="Login" action="#{personController.submit()}" ajax="false"/>
</f:facet>
</h:panelGrid>
</p:panel>
</h:form>
</h:body>
</html>
@@ -1,14 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}</title>
</h:head>
<h:body>
<p>Willkommen #{personController.activeUser.call.toString()} #{personController.activeUser.lastname}</p>
<p:spinner />
</h:body>
</html>
@@ -1,21 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
-->
<libraries xmlns="http://www.netbeans.org/ns/cdnjs-libraries/1"/>
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>1.8-web</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
<org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>ide</org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>
<org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language>
</properties>
</project-shared-configuration>
-->
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>8.0-web</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
<org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>ide</org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>
<org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language>
<org-netbeans-modules-css-prep.less_2e_mappings>/less:/css</org-netbeans-modules-css-prep.less_2e_mappings>
<org-netbeans-modules-css-prep.less_2e_enabled>false</org-netbeans-modules-css-prep.less_2e_enabled>
<org-netbeans-modules-css-prep.sass_2e_enabled>false</org-netbeans-modules-css-prep.sass_2e_enabled>
<org-netbeans-modules-css-prep.sass_2e_compiler_2e_options/>
<org-netbeans-modules-css-prep.less_2e_compiler_2e_options/>
<org-netbeans-modules-css-prep.sass_2e_mappings>/scss:/css</org-netbeans-modules-css-prep.sass_2e_mappings>
<org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder>js/libs</org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder>
</properties>
</project-shared-configuration>
Regular → Executable
+185 -70
View File
@@ -1,78 +1,193 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>plate.software</groupId>
<artifactId>mss-failsafe</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<modelVersion>4.0.0</modelVersion>
<groupId>plate.software</groupId>
<artifactId>mss</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mss-1.0-SNAPSHOT</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
<jakartaee>8.0</jakartaee>
</properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>mssfailsafe.datalayer</module>
<module>userdata</module>
<module>mssfailsafeWeblayer</module>
<module>mss</module>
</modules>
<name>mss-failsafe</name>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.5.Final</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>io</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>forms</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdfa</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>sign</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>barcodes</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>7.2.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>hyph</artifactId>
<version>7.2.2</version>
</dependency>
<!--
<dependency>
<groupId>org.glassfish.soteria</groupId>
<artifactId>javax.security.enterprise</artifactId>
<version>1.0</version>
</dependency>-->
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.11.1</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>11.0.0</version>
</dependency>
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>primeflex</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>11</source>
<target>11</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${jakartaee}</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,197 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import model.AbstractEntity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Hibernate;
/**
*
* @author Patrick
* @param <T>
*/
public abstract class AbstractManager<T extends AbstractEntity> {
protected final Logger LOGGER = LogManager.getLogger(this.getClass());
private final Class<T> entityClass;
public AbstractManager(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
@Transactional
public boolean save(T entity) {
if (entity == null) {
return false;
}
if (entity.getId() != null) {
try {
edit(entity);
getEntityManager().flush();
} catch (Exception e) {
LOGGER.error(e);
return false;
}
} else {
try {
create(entity);
getEntityManager().flush();
} catch (Exception e) {
LOGGER.error(e);
return false;
}
}
return true;
}
@Transactional
public boolean saveAll(Collection<T> entities) {
if (entities == null) {
return false;
}
if (entities.isEmpty()) {
return true;
}
for (T entity : entities) {
if (entity.getId() != null) {
try {
edit(entity);
} catch (Exception e) {
LOGGER.error(e);
return false;
}
} else {
try {
create(entity);
} catch (Exception e) {
LOGGER.error(e);
return false;
}
}
}
getEntityManager().flush();
return true;
}
public void create(T entity) {
try {
getEntityManager().persist(entity);
} catch (Exception e) {
LOGGER.error(e);
}
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public T refresh(T entity) {
if (entity == null) {
return null;
}
if (entity.getId() == null) {
save(entity);
}
entity = getEntityManager().merge(entity);
Hibernate.initialize(entity);
return entity;
}
public boolean removeAllIn(Collection<T> col) {
if (col == null || col.isEmpty()) {
return true;
}
try {
boolean success = true;
for (T entity : col) {
if (!remove(entity)) {
success = false;
}
}
return success;
} catch (Exception e) {
LOGGER.error(e);
}
return false;
}
public boolean remove(T entity) {
if (entity == null || entity.getId() == null) {
return false;
}
try {
Hibernate.initialize(entity);
entity = find(entity.getId());
getEntityManager().remove(entity);
return true;
} catch (Exception e) {
LOGGER.error(e);
return false;
}
/*
String queryString = "DELETE FROM " + entityClass.getSimpleName() + " e WHERE e.id = :id";
Query query = getEntityManager().createQuery(queryString);
query.setParameter("id", entity.getId());
try {
query.executeUpdate();
return true;
} catch (Exception e) {
LOGGER.error(e);
return false;
}*/
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0] + 1);
q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
@@ -0,0 +1,74 @@
package business;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
@Named
@SessionScoped
public class BackupFileManager implements Serializable {
private static final Logger logger = LogManager.getLogger(BackupFileManager.class);
private static final String BACKUP_DIRECTORY = "/h2DB/";
private List<File> backupFiles;
@PostConstruct
public void init() {
loadBackupFiles();
}
public void loadBackupFiles() {
File directory = new File(BACKUP_DIRECTORY);
if (directory.exists() && directory.isDirectory()) {
File[] files = directory.listFiles((dir, name) -> name.startsWith("h2-mss-database-backup_") && name.endsWith(".zip"));
if (files != null) {
backupFiles = Arrays.asList(files);
// Sortiere Dateien nach Änderungsdatum (neueste zuerst)
Collections.sort(backupFiles, (f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()));
} else {
backupFiles = Collections.emptyList();
}
} else {
backupFiles = Collections.emptyList();
logger.warn("Backup-Verzeichnis existiert nicht: " + BACKUP_DIRECTORY);
}
}
public List<File> getBackupFiles() {
return backupFiles;
}
public StreamedContent downloadFile(String fileName) {
try {
File file = new File(BACKUP_DIRECTORY + fileName);
return DefaultStreamedContent.builder()
.name(fileName)
.contentType("application/zip")
.stream(() -> {
try {
return new FileInputStream(file);
} catch (IOException e) {
logger.error("Fehler beim Lesen der Backup-Datei: " + fileName, e);
return null;
}
})
.build();
} catch (Exception e) {
logger.error("Fehler beim Vorbereiten des Downloads für: " + fileName, e);
return null;
}
}
}
@@ -0,0 +1,156 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Attribute;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
*
* @author patri
*/
@Stateless
@Named
public class ChangeToCLOBManager {
// Inject the Logger
private static final Logger logger = LogManager.getLogger(ChangeToCLOBManager.class);
@PersistenceContext
private EntityManager em;
@javax.ejb.Asynchronous
public void checkColumnType() {
/*
Map<String, List<String>> tables_values = checkLobAnnotations(em);
logger.info("running check for table values!");
tables_values.forEach((table, columns) -> {
if (columns == null || columns.isEmpty()) {
return;
}
logger.info("looking for fields in {}", table);
// Check if the column's data type is VARCHAR
columns.stream().filter(col -> (isVarcharColumn(em, table, col))).map(col -> {
// Change the column's data type to CLOB
changeColumnType(em, table, col);
return col;
}).forEachOrdered(col -> {
logger.info("Changed column type to CLOB of table: {}; column: {}", table, col);
});
});*/
}
private boolean isVarcharColumn(EntityManager em, String tableName, String columnName) {
// Construct the native SQL query
String nativeSql = "SELECT TYPE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?1 AND COLUMN_NAME = ?2";
// Create a native Query
Query nativeQuery = em.createNativeQuery(nativeSql);
// Set the parameters for the query
nativeQuery.setParameter(1, tableName.toUpperCase());
nativeQuery.setParameter(2, columnName.toUpperCase());
logger.info("Added parameters 1: {}; 2:{}", tableName.toUpperCase(), columnName.toUpperCase());
String dataType = null;
// Execute the query and get the result
try {
dataType = (String) nativeQuery.getSingleResult();
} catch (NoResultException e) {
logger.info("NoResult", e);
}
// Return true if the column's data type is VARCHAR, false otherwise
return dataType != null ? "VARCHAR".equalsIgnoreCase(dataType) : false;
}
private void changeColumnType(EntityManager em, String tableName, String columnName) {
// Construct the native SQL query
String nativeSql = "ALTER TABLE " + tableName.toUpperCase() + " MODIFY COLUMN " + columnName.toUpperCase() + " CLOB";
logger.info(nativeSql);
// Create a native Query
Query nativeQuery = em.createNativeQuery(nativeSql);
// Execute the query
nativeQuery.executeUpdate();
}
private Map<String, List<String>> checkLobAnnotations(EntityManager em) {
// Create a Map to store the results
Map<String, List<String>> results = new HashMap<>();
// Get the Metamodel from the EntityManager
Metamodel metamodel = em.getMetamodel();
// Iterate over all the managed types
for (ManagedType<?> managedType : metamodel.getManagedTypes()) {
// Check if the managed type is an Entity
if (managedType.getJavaType().isAnnotationPresent(Entity.class)) {
// Get the EntityType for the managed type
EntityType<?> entityType = (EntityType<?>) managedType;
// Get the table name
// Iterate over all the attributes
for (Attribute<?, ?> attribute : entityType.getAttributes()) {
String tableName = entityType.getName();
String columnName = attribute.getName();
try {
logger.info(entityType.getJavaType().getName());
Class<?> cl = getClass().getClassLoader().loadClass(entityType.getJavaType().getName());
Field[] fields = getClass().getClassLoader().loadClass(entityType.getJavaType().getName()).getFields();
for(Field field : fields){
field.setAccessible(true);
logger.info(field.getName());
if (field.isAnnotationPresent(Lob.class)) {
logger.info("Field with lob class!!!");
}
}
logger.info("entity name : {}; attribute name: {}; isLob: {}", tableName, columnName, "todo");
} catch (SecurityException ex) {
logger.error("Security");
} catch (ClassNotFoundException ex) {
logger.error("Classnot");
}
// Check if the element has the @Lob annotation
if (attribute.getJavaType().isAnnotationPresent(Lob.class)) {
logger.info("Attribute " + attribute.getName() + " in " + entityType.getName() + " has @Lob annotation");
if (!results.containsKey(tableName)) {
results.put(tableName, new ArrayList<>());
}
results.get(tableName).add(columnName);
}
}
}
}
return results;
}
}
@@ -0,0 +1,60 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Named
@Startup
@Singleton
public class DatabaseBackupManager {
private static final Logger logger = LogManager.getLogger(DatabaseBackupManager.class);
@EJB
private ChangeToCLOBManager changeToCLOBManager;
@PersistenceContext(unitName="pu_person")
private EntityManager entityManager;
@Schedule(hour="4", minute = "0", second = "0", persistent = true)
public void createDatabaseBackup() {
// Get the current date and time
LocalDateTime now = LocalDateTime.now();
// Format the date and time to be included in the filename
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
String formattedDateTime = now.format(formatter);
// Create the backup filename
String backupFilename = "/h2DB/h2-mss-database-backup_" + formattedDateTime + ".zip";
// Use the EntityManager to create a backup of the H2 database
entityManager.createNativeQuery("BACKUP TO '" + backupFilename + "'")
.executeUpdate();
// Log a message indicating that the backup was successful
logger.info("Successfully created H2 database backup: " + backupFilename);
}
@PostConstruct
private void init(){
changeToCLOBManager.checkColumnType();
}
}
@@ -0,0 +1,80 @@
package business;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
@Named
@SessionScoped
public class LogFileManager implements Serializable {
private static final Logger logger = LogManager.getLogger(LogFileManager.class);
private static final String LOG_DIRECTORY = "/logs/";
private List<File> logFiles;
@PostConstruct
public void init() {
loadLogFiles();
}
public void loadLogFiles() {
File directory = new File(LOG_DIRECTORY);
if (directory.exists() && directory.isDirectory()) {
File[] files = directory.listFiles((dir, name) -> name != null && name.startsWith("application.log"));
if (files != null) {
logFiles = Arrays.asList(files);
Collections.sort(logFiles, (f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()));
} else {
logFiles = Collections.emptyList();
}
} else {
logFiles = Collections.emptyList();
logger.warn("Log-Verzeichnis existiert nicht: " + LOG_DIRECTORY);
}
}
public List<File> getLogFiles() {
return logFiles;
}
public StreamedContent downloadFile(String fileName) {
try {
final File file = new File(LOG_DIRECTORY + fileName);
final String contentType;
if (fileName.endsWith(".gz")) {
contentType = "application/gzip";
} else if (fileName.endsWith(".log")) {
contentType = "text/plain";
} else {
contentType = "application/octet-stream";
}
return DefaultStreamedContent.builder()
.name(fileName)
.contentType(contentType)
.stream(() -> {
try {
return new FileInputStream(file);
} catch (IOException e) {
logger.error("Fehler beim Lesen der Log-Datei: " + fileName, e);
return null;
}
})
.build();
} catch (Exception e) {
logger.error("Fehler beim Vorbereiten des Downloads für Log-Datei: " + fileName, e);
return null;
}
}
}
@@ -0,0 +1,111 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business;
import javax.ejb.Stateless;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.inject.Named;
import javax.mail.MessagingException;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Named
@Stateless
public class PasswordResetEJB {
protected final Logger LOGGER = LogManager.getLogger(PasswordResetEJB.class);
// Set up the email server properties
private static final String SMTP_SERVER = "smtp.gmail.com";
private static final String USERNAME = "dein@user.gmail.com";
private static final String PASSWORD = "HierStehtDeinPasswort";
// Set up the email message properties
private static final String EMAIL_SUBJECT = "Password Reset Request";
private static final String EMAIL_BODY
= "Sehr geehrte/r %s,\n\n"
+ "Sie haben angefordert, Ihr Passwort zurückzusetzen. Bitte klicken Sie auf den unten stehenden Link, um fortzufahren:\n\n"
+ "%s\n\n"
+ "Wenn Sie diese Anfrage nicht gestellt haben, ignorieren Sie bitte diese E-Mail.\n\n"
+ "Bitte beachten Sie, dass der Link nur einmal verwendet werden kann und innerhalb von 24 Stunden ab Erhalt dieser E-Mail abläuft.\n\n"
+ "Wenn Sie weitere Fragen haben, zögern Sie bitte nicht, uns zu kontaktieren.\n\n"
+ "Freundliche Grüße,\n\n"
+ "%s";
private static final String COMPANY
= "MSS Machine Safety Services\n"
+ "+49162 1322 382\n"
+ "kontakt@mss-failsafe.com\n"
+ "Lüneburger Str. 48\n"
+ "28870 Ottersberg";
private static final String imagePath = "/resources/images/logos/logo_small.png";
private static DataSource dataSource;
public boolean sendPasswordResetEmail(String to, String name, String resetLink) {
if (dataSource == null) {
dataSource = new FileDataSource(imagePath);
}
// Set up the email server properties
Properties prop = new Properties();
prop.put("mail.smtp.host", SMTP_SERVER);
prop.put("mail.smtp.port", "587");
prop.put("mail.smtp.auth", "true");
prop.put("mail.smtp.starttls.enable", "true");
try {
// Set up the email session
Session session = Session.getInstance(prop, null);
// Create a MimeMultipart object to hold the text and image parts of the email
MimeMultipart multipart = new MimeMultipart("related");
// Create a MimeBodyPart object to hold the text of the email
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(getFormattedMessage(name, resetLink));
multipart.addBodyPart(messageBodyPart);
// Create a MimeBodyPart object to hold the image
//MimeBodyPart imagePart = new MimeBodyPart();
//imagePart.setDataHandler(new DataHandler(dataSource));
//imagePart.setHeader("Content-ID", "MSS Machine Safety Services");
//multipart.addBodyPart(imagePart);
// Set up the email message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(USERNAME));
message.setRecipients(Message.RecipientType.TO, to);
message.setSubject(EMAIL_SUBJECT);
message.setContent(multipart);
// Send the email message
Transport transport = session.getTransport("smtp");
transport.connect(SMTP_SERVER, USERNAME, PASSWORD);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
return true;
} catch (MessagingException e) {
LOGGER.error(e);
}
return false;
}
private String getFormattedMessage(String name, String resetLink) {
return String.format(EMAIL_BODY, name, resetLink, COMPANY);
}
}
@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.addresses;
import business.AbstractManager;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import model.company.Location;
/**
*
* @author patri
*/
@Named
@Stateless
public class CompanyAddressManager extends AbstractManager<Location>{
@PersistenceContext(name = "pu_person")
EntityManager em;
public CompanyAddressManager() {
super(Location.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
@@ -0,0 +1,35 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.addresses;
import business.AbstractManager;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import model.company.Location;
/**
*
* @author patri
*/
@Named
@Stateless
public class LocationAddressManager extends AbstractManager<Location>{
@PersistenceContext(name = "pu_person")
EntityManager em;
public LocationAddressManager() {
super(Location.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
@@ -0,0 +1,34 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package business.company;
import business.AbstractManager;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import model.company.CompanyLogo;
/**
*
* @author pplate
*/
@Named
@Stateless
public class CompanyLogoManager extends AbstractManager<CompanyLogo>{
@PersistenceContext(name = "pu_person")
EntityManager em;
public CompanyLogoManager() {
super(CompanyLogo.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
@@ -0,0 +1,139 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.company;
import business.AbstractManager;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import model.company.Company;
import model.company.Location;
import model.machine.Machine;
import org.hibernate.Hibernate;
import java.util.List;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
/**
*
* @author patri
*/
@Named
@Stateless
public class CompanyManager extends AbstractManager<Company> {
@PersistenceContext(name = "pu_person")
EntityManager em;
private static final String loadWithCollectionQuery =
"SELECT DISTINCT c FROM Company c " +
"LEFT JOIN FETCH c.addresses " +
"LEFT JOIN FETCH c.locations l " +
"LEFT JOIN FETCH l.machines m " +
"LEFT JOIN FETCH m.securityArea sa " +
"LEFT JOIN FETCH sa.securityDevices " +
"LEFT JOIN FETCH sa.dangerPoints " +
"LEFT JOIN FETCH sa.switchingDevices " +
"LEFT JOIN FETCH sa.questionnaires " +
"WHERE c.id = :companyId";
public CompanyManager() {
super(Company.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
@Transactional
public Company findWithAddresses(Company selected) {
Company loaded = null;
/*
try {
return em.createQuery(loadWithCollectionQuery, Company.class)
.setParameter("companyId", selected.getId())
.getSingleResult();
} catch (NoResultException e) {
return null;
}
*/
try {
loaded = find(selected.getId());
Hibernate.initialize(loaded);
loaded.getLocations().stream()
.map(Location::getMachines)
.flatMap(List::stream)
.map(Machine::getSecurityArea)
.flatMap(List::stream)
.forEach(area -> {
Hibernate.initialize(area.getSecurityDevices());
Hibernate.initialize(area.getDangerPoints());
Hibernate.initialize(area.getSwitchingDevices());
Hibernate.initialize(area.getQuestionnaires());
if (area.getQuestionnaires() != null) {
area.getQuestionnaires().forEach(q -> Hibernate.initialize(q.getQuestions()));
}
});
//loaded.getLocations().size();
//loaded.getAddresses().size();
//loaded.getCustomers().size();
} catch (Exception e) {
LOGGER.error(e);
}
return loaded;
}
public Company findCompanyByName(String name) {
TypedQuery<Company> query = em.createNamedQuery(Company.FIND_BY_NAME, Company.class);
query.setParameter("name", name);
try {
Company loaded = query.getSingleResult();
if (loaded != null) {
Hibernate.initialize(loaded.getAddresses());
loaded.getLocations().stream()
.map(Location::getMachines)
.flatMap(List::stream)
.map(Machine::getSecurityArea)
.flatMap(List::stream)
.forEach(area -> {
Hibernate.initialize(area.getSecurityDevices());
Hibernate.initialize(area.getDangerPoints());
Hibernate.initialize(area.getSwitchingDevices());
});
}
return loaded;
} catch (NoResultException noRe) {
return null;
} catch (Exception e) {
LOGGER.error(e);
}
return null;
}
public Company findWithLocations(Company selected) {
Company loaded = null;
try {
loaded = find(selected.getId());
loaded.getCustomers().size();
loaded.getLocations().size();
} catch (Exception e) {
LOGGER.error(e);
}
return loaded;
}
}
@@ -0,0 +1,53 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.company;
import business.AbstractManager;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import model.customer.Customer;
/**
*
* @author patri
*/
@Stateless
@Named
public class CustomerManager extends AbstractManager<Customer>{
@PersistenceContext(name = "pu_person")
EntityManager em;
public CustomerManager() {
super(Customer.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
public Customer findByEmail(String email){
Customer result = null;
if (email == null || email.isEmpty()) {
return result;
}
TypedQuery<Customer> query = em.createNamedQuery(Customer.GET_BY_EMAIL, Customer.class);
query.setParameter("email", email);
try {
result = query.getSingleResult();
} catch (Exception e) {
LOGGER.info(e);
}
return result;
}
}
@@ -0,0 +1,49 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package business.company;
import business.AbstractManager;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import model.company.Location;
/**
*
* @author patri
*/
@Named
@Stateless
public class LocationManager extends AbstractManager<Location>{
@PersistenceContext(name = "pu_person")
EntityManager em;
public LocationManager() {
super(Location.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
public Location loadWithMachines(Long id){
if (id == null) {
return null;
}
try {
Location loc = find(id);
loc.getMachines().size();
return loc;
} catch (Exception e) {
LOGGER.error(e);
return null;
}
}
}
@@ -0,0 +1,36 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package business.machine;
import business.AbstractManager;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import model.machine.Contact;
/**
*
* @author pplate
*/
@Named
@Stateless
public class ContactManager extends AbstractManager<Contact>{
@PersistenceContext(name = "pu_person")
EntityManager em;
public ContactManager() {
super(Contact.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
@@ -0,0 +1,77 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package business.machine;
import business.AbstractManager;
import java.util.Collection;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import model.AbstractEntity;
import model.security.DangerPoint;
import model.security.MeasuringPoint;
import org.hibernate.Hibernate;
/**
*
* @author pplate
*/
@Named
@Stateless
public class DangerPointManager extends AbstractManager<DangerPoint> {
@PersistenceContext(name = "pu_person")
EntityManager em;
@EJB
MeasuringPointManager measuringPointManager;
public DangerPointManager() {
super(DangerPoint.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
@Override
public boolean remove(DangerPoint entity) {
entity = em.find(DangerPoint.class, entity.getId());
Hibernate.initialize(entity.getMeasuringPoint());
if (entity.getMeasuringPoint() != null) {
entity.getMeasuringPoint().setDangerPoint(null);
em.remove(entity.getMeasuringPoint());
//measuringPointManager.remove(entity.getMeasuringPoint());
entity.setMeasuringPoint(null);
}
entity = em.find(DangerPoint.class, entity.getId());
em.remove(entity);
//save(entity);
//return super.remove(entity);
return true;
}
@Override
public boolean removeAllIn(Collection<DangerPoint> col) {
for (DangerPoint dp : col) {
if (dp.getMeasuringPoint() != null) {
dp.getMeasuringPoint().setDangerPoint(null);
MeasuringPoint pt = dp.getMeasuringPoint();
dp.setMeasuringPoint(null);
measuringPointManager.save(pt);
measuringPointManager.remove(pt);
}
dp.setSecurityArea(null);
save(dp);
}
return super.removeAllIn(col);
}
}

Some files were not shown because too many files have changed in this diff Show More